Sending GMail with attachment from Android app [duplicate] - android

My app writes data to text files (on sd card and internal memory).
Later the app emails the text files to a list of people.
I am having trouble getting gmail to attach a file that is pulled from the internal application files area. 'Native Android mail' can attach a file from either internal or SD card area with no problem. Gmail will attach a file if it's from SD card, but won't attach a file if its located in internal storage.
// this sends a file from SD - works for android mail and gmail
Intent jj=new Intent(android.content.Intent.ACTION_SEND);
String fileName = "file://" + Environment.getExternalStorageDirectory()+"/aFolder/externalfile.txt"
jj.putExtra(Intent.EXTRA_STREAM, Uri.parse(fileName));
jj.setType("text/plain");
Intent chooser = Intent.createChooser(jj , "Select Sender");
startActivity(chooser);
// this sends an internal file-works for android mail, but no attachment sent with gmail
Intent jj=new Intent(android.content.Intent.ACTION_SEND);
String fileName = "file://" + getFilesDir().toString() + "/internalfile.txt";
jj.putExtra(Intent.EXTRA_STREAM, Uri.parse(fileName));
jj.setType("text/plain");
Intent chooser = Intent.createChooser(jj , "Select Sender");
startActivity(chooser);
Any suggestions?
Do I need to give Gmail special permission somehow?
My attachments are all text files - written by the app.
Internal files were created with openFileOutput(myFile,32769)
Thanks
John D

the only way I found around this was to make my own content provider and pass in the uri to my content provider as the attachment.

Like Dhego, I used a content provider. Specifically, a FileProvider.
https://developer.android.com/reference/android/support/v4/content/FileProvider.html
Using this only requires that you modify your Manifest and create an additional resource file. Also, you will need to obtain a validly formatted URI via a static method provided by FileProvider.
In your Manfiest:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.authority.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
The "com.example.authority.fileprovider" is your application authority with "fileprovider" appended.
In the res/xml folder, create a file_paths.xml file that contains the paths to the files you want to expose. In my case, I was exposing them from the application cache directory, so my XML looks like:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="reports" path="reports/"/>
</paths>
In my case, "reports" is a folder within the application cache directory that I am writing files to.
The last thing to do is in your code:
Write files you want to expose to the folders and storage areas specified in file_paths.xml.
Generate a valid URI to set on the Intent you will invoke for sending an email (Intent.ACTION_SEND).
Here's some sample code:
emailIntent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(getActivity(), "com.example.authority.fileprovider", fileToAttach));
Invoke startActivity on your Intent and that should be it!

It appears that there is indeed an issue with gmail. Unfortunately however, at the time of the writing it seems it hasn't been fixed.

Related

Android: Send e-mail via intent with file as attachment

There are many posts on this topic, but I can't find the solution for my problem...
Following: I would like to send a file out of my app via an e-mail attachment.
Sending the file via Whatsapp, save to Google Drive,... works, but not for K-9 Mail or Gmail ("Unable to attache file" Toast message is displayed).
Intent intentShareFile = new Intent(Intent.ACTION_SEND);
intentShareFile.setType("application/zip");
intentShareFile.putExtra(Intent.EXTRA_STREAM, Uri.parse("/sdcard/Download/ExportFile.zip"));
//intentShareFile.putExtra(Intent.EXTRA_TEXT, "message");
intentShareFile.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intentShareFile.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivity(Intent.createChooser(intentShareFile, "Share File"));
I don't understand why it works for all apps, except e-mail apps.
Can anyone help me out?Thanks in advance.
I think your issue is related to the path of the file you are using here (i.e Uri.parse("/sdcard/Download/ExportFile.zip"))
There is a code example to send an email with an attachment on the Android Developers docs here. In the example they pass the Uri as follows:
Uri.parse("content://path/to/email/attachment"). Notice this is called a ContentUri, read more about it form here.
Hope this turns useful for you!
Amr EIZawawy is right. I need to create the Uri of the file and use the File Provider API.
I don't know if I did too much, but this is my solution:
Create a file called "file_paths.xml" in a directory "xml" (create first) within your "res" directory (sibling of layout directory).
The file needs to contain the path to the file you want to share. For the external Download directory this is:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="download" path="Download/"/>
</paths>
// The internal path you'd be <files-path name.../> see [FileProvider][1] for all possibilities
Define the File provider within the AndroidManifest.xml with a meta-data link to the just created XML file:
<application
...
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.<your-app-package-name>.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" /> // Link to the above created file
</provider>
...
Implement the code:
Intent intentShareFile = new Intent(Intent.ACTION_SEND);
intentShareFile.setType("application/zip");
File fileDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
File newFile = new File(fileDirectory, "ExportFile.zip");
String authority = "com.bennoss.myergometertrainer.fileprovider"; // Must be the same as in AndroidManifest.
Uri contentUri = FileProvider.getUriForFile(getContext(), authority, newFile);
intentShareFile.putExtra(Intent.EXTRA_STREAM, contentUri);
//intentShareFile.putExtra(Intent.EXTRA_TEXT, "xxx");
intentShareFile.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(intentShareFile, "Share File"));
For more information see: FileProvider

Android Attaching a file to GMAIL - Can't attach empty file

I had a program that would always attach the same file to GMAIL (Compose > Attach File > Open From > "MyProgram"). It would always select the same file.
What it was doing was:
String path = Environment.getExternalStorageDirectory() + "/file.3gp";
File f = new File(path);
Uri data = Uri.fromFile(f);
Intent i = new Intent();
i.setData(data);
setResult(Activity.RESULT_OK, i);
finish();
This was working fine until Android 6.0.
Now, I receive the following error when trying to use it:
Can't attach empty file
Astro File Sharing is giving me the same error (can be an old build).
However, I installed ES File Explorer, and when I do the same routine, and select the file, I receive a Dialog which says:
Pick up file as
Normal Android Way (For MMS,Gmail,...)
File Way (Try this if above fails)
The "File Way" will fail as my program does. The "Normal Android Way" will work fine.
Does anyone have any idea on what it does, so I can replicate?
Thanks in advance!
OBS: Already tried the putExtra(STREAM, path) a lot of times, but without success.
Ok, got it to work now, after a lot of research and intercepting some Intents.
What I had to do was change the file:/// to content://.
I did this following this information from Android: https://developer.android.com/reference/android/support/v4/content/FileProvider.html
The only major change was that I used a hard-coded path to /sdcard/file.ext.
Also, the line
getUriForFile(getContext(), "com.mydomain.fileprovider", newFile);
was changed to
Uri contentUri = FileProvider.getUriForFile(this, "com.mydomain.fileprovider", newFile);
Also had to include:
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
i.setData(contentUri);
I do not really understand why I had to change from File to Content, but after this, the file is now being attached again! See the link if you face this issue, and don't forget about the new .xml that needs to be created.
See the following question:
android-6-cannot-share-files-anymore
This behavior is with Android 6.0 and Gmail. Please see the following thread.
Issue 3141 - android-developer-preview
If you go to Settings->Apps->Gmail->Permissions and enable the
"Storage" permission manually, then the share works.
Gmail should ask for "Storage" permission in this scenario and it
would work as it did in all the past version of Android.
Other email apps should handle attachments correctly.
Here is how to fix it.
Go to Settings -> Apps -> Gmail -> Permissions
Turn on the permission for "Storage"
That work-around solved the issue for me.
I couldn't find a clear answer(sending an attachment on gmail without SD card) I tried to copy to another file name but no cigar. The way I got it to work was copy to the Downloads folder and go from there.
Get the path for Downloads with this
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
pulls the full path to downlaods folder copy the attachemnt to there and we are good. Files over 20M don't go
Share any file using INTENT provided given file path
//File file= shareable File Path
Uri uri = FileProvider.getUriForFile(this, "com.example.myapp.fileprovider", file);
//FileProvider authorities from Manifest
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.setType("*/*");
sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(sharingIntent);
Just match your authorities from the manifest in arguments of method getUriForFile.
In Manifest
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths" />
</provider>

File provider - Files not accessible even in the own app

I am implementing a File Provider, followed the doc carefully but unable to use the files in the app itself or share any file.
Added manifest, created xml file for dir sharing, generating content uri, granting uri permission, tried sharing files with cache, external, internal dir but nothing is working.
Searched the net but found nothing which is missing in the code.
Below is the code:
Manifest:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="package.widget.fileprovider"
android:exported="false"
android:grantUriPermissions="true" >
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths" />
</provider>
filepaths.xml
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="widgetDoc" path="."/>
</paths>
GetUri:
private Uri getFileUri(Context context, String name){
File newFile = new File(context.getCacheDir() + File.separator + StorageUtil.INTERNAL_DIR, name);
Uri contentUri = FileProvider.getUriForFile(context, "package.widget.fileprovider", newFile);
return contentUri;
}
Code to access pdf file:
Intent target = new Intent(Intent.ACTION_VIEW);
Uri uri = getFileUri(getApplicationContext(), file);
target.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
target.setDataAndType(uri,"application/pdf");
Intent intent = Intent.createChooser(target, "Choose Pdf Viewer...");
startActivity(intent);
Code to access image:
imageview.setImageURI(getFileUri(getApplicationContext(), file));
Kindly help me out where I am going wrong, not even able to use these files in my own app too.
Thanks in advance.
I need to show these image files in a widget and now if am accessing the image files from the widget then it is giving IllegalArgumentException: Failed to find configured root however it is working fine with activity
Ideally, use setImageViewBitmap(), and make sure that your image is small (under 1MB in heap space, such as less than 512x512).
While the RemoteViews can accept a Uri, you have good way of associating Intent.FLAG_GRANT_READ_URI_PERMISSION with a RemoteViews for the purposes of populating an ImageView. And, you cannot export your FileProvider, as FileProvider does not allow that.
You can attempt to identify the user's chosen home screen and use grantUriPermission() to grant the home screen access to this Uri, but I would expect that solution to be fragile.

Send email with attachment from internal storage

I create file on the internal storage as suggested by android docs. To be accurate the file is created under a specific directory in the internal storage. I do this using the mode world_readable mode. Then later on i try to attach the file using email program. I was able to get the file attached, however sending the email failed (does not seem to be to load the file) i am sure it is internal storage/permission thingy.
Anyone knows how to fix it or a working example? It will suck to have convert everything on external storage.
Thank you
Ps:I checked other threads and they don't seem to have solutions (old threads)
It is possible to share a file from your apps local storage to another application (such as email attachment) by granting temporary permissions to read that file as part of the share intent.
Step 1: Add a file provider to your AndroidManifest.xml:
<applicaton>
....
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.your.package.name.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths" />
</provider>
</application>
Step 2: Add a file res/xml/filepaths.xml with the path to the file in local app storage that you want to share:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="myFolder" path="Folder/"/>
</paths>
Step 3: In your java code create the file sharing intent:
Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND_MULTIPLE);
shareIntent.setType("text/plain");
shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Your subject");
shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, "Your message");
ArrayList<Uri> uris = new ArrayList<Uri>();
String shareName = new String(pathToFile + filename);
File shareFile = new File(shareName);
Uri contentUri = FileProvider.getUriForFile(context, "com.your.package.name.fileprovider", shareFile);
uris.add(contentUri);
shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
// Grant temporary read permission to the content URI
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
String msgStr = "Share...";
startActivity(Intent.createChooser(shareIntent, msgStr));
If you have any problems with it see the docs here
https://developer.android.com/training/secure-file-sharing/share-file.html for further details.
I'm assuming you are trying to send the file as an email attachment
using intents.
The reason why the file is empty is that the email app does not have
access to the file in /data/data/package_name/myfile_name, due to
Androids security model (the /data/data/package_name directory is
private to your app).
In order to add the file as an attachment, you need to write it to
public storage (such as the SD card) so the email app can access it.

Problem Attaching internal file to GMail in my android app

My app writes data to text files (on sd card and internal memory).
Later the app emails the text files to a list of people.
I am having trouble getting gmail to attach a file that is pulled from the internal application files area. 'Native Android mail' can attach a file from either internal or SD card area with no problem. Gmail will attach a file if it's from SD card, but won't attach a file if its located in internal storage.
// this sends a file from SD - works for android mail and gmail
Intent jj=new Intent(android.content.Intent.ACTION_SEND);
String fileName = "file://" + Environment.getExternalStorageDirectory()+"/aFolder/externalfile.txt"
jj.putExtra(Intent.EXTRA_STREAM, Uri.parse(fileName));
jj.setType("text/plain");
Intent chooser = Intent.createChooser(jj , "Select Sender");
startActivity(chooser);
// this sends an internal file-works for android mail, but no attachment sent with gmail
Intent jj=new Intent(android.content.Intent.ACTION_SEND);
String fileName = "file://" + getFilesDir().toString() + "/internalfile.txt";
jj.putExtra(Intent.EXTRA_STREAM, Uri.parse(fileName));
jj.setType("text/plain");
Intent chooser = Intent.createChooser(jj , "Select Sender");
startActivity(chooser);
Any suggestions?
Do I need to give Gmail special permission somehow?
My attachments are all text files - written by the app.
Internal files were created with openFileOutput(myFile,32769)
Thanks
John D
the only way I found around this was to make my own content provider and pass in the uri to my content provider as the attachment.
Like Dhego, I used a content provider. Specifically, a FileProvider.
https://developer.android.com/reference/android/support/v4/content/FileProvider.html
Using this only requires that you modify your Manifest and create an additional resource file. Also, you will need to obtain a validly formatted URI via a static method provided by FileProvider.
In your Manfiest:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.authority.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
The "com.example.authority.fileprovider" is your application authority with "fileprovider" appended.
In the res/xml folder, create a file_paths.xml file that contains the paths to the files you want to expose. In my case, I was exposing them from the application cache directory, so my XML looks like:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="reports" path="reports/"/>
</paths>
In my case, "reports" is a folder within the application cache directory that I am writing files to.
The last thing to do is in your code:
Write files you want to expose to the folders and storage areas specified in file_paths.xml.
Generate a valid URI to set on the Intent you will invoke for sending an email (Intent.ACTION_SEND).
Here's some sample code:
emailIntent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(getActivity(), "com.example.authority.fileprovider", fileToAttach));
Invoke startActivity on your Intent and that should be it!
It appears that there is indeed an issue with gmail. Unfortunately however, at the time of the writing it seems it hasn't been fixed.

Categories

Resources