Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gmail 5.0 app fails with "Permission denied for the attachment" when it receives ACTION_SEND intent

My app creates mails with attachments, and uses an intent with Intent.ACTION_SEND to launch a mail app.

It works with all the mail apps I tested with, except for the new Gmail 5.0 (it works with Gmail 4.9), where the mail opens without attachment, showing the error: "Permission denied for the attachment".

There are no useful messages from Gmail on logcat. I only tested Gmail 5.0 on Android KitKat, but on multiple devices.

I create the file for the attachment like this:

String fileName = "file-name_something_like_this";
FileOutputStream output = context.openFileOutput(
        fileName, Context.MODE_WORLD_READABLE);

// Write data to output...

output.close();
File fileToSend = new File(context.getFilesDir(), fileName);

I'm aware of the security concerns with MODE_WORLD_READABLE.

I send the intent like this:

public static void compose(
        Context context,
        String address,
        String subject,
        String body,
        File attachment) {

    Intent emailIntent = new Intent(Intent.ACTION_SEND);
    emailIntent.setType("message/rfc822");
    emailIntent.putExtra(
            Intent.EXTRA_EMAIL, new String[] { address });
    emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
    emailIntent.putExtra(Intent.EXTRA_TEXT, body);

    emailIntent.putExtra(
            Intent.EXTRA_STREAM,
            Uri.fromFile(attachment));

    Intent chooser = Intent.createChooser(
            emailIntent, 
            context.getString(R.string.send_mail_chooser));

    context.startActivity(chooser);
}

Is there anything I do wrong when creating the file or sending the intent? Is there a better way to start a mail app with attachment? Alternatively - has someone encountered this problem and found a workaround for it?

Thanks!

like image 773
natasky Avatar asked Nov 12 '14 09:11

natasky


People also ask

Why can't I open attachments in Gmail app?

Why can't I see attachments in Gmail on phone? Try clearing the GMail app cache (and data if necessary). There are different paths for this on different phones: Open the Settings app, then go to Storage & USB > Apps > Gmail. Open the Settings app, then go to App Management > Gmail > Storage Usage.

Why is my Gmail not sending attachments on my phone?

Attachments might be unavailableYour network administrator or Internet provider probably blocked "mail-attachment.googleusercontent.com," the domain Google uses to host attachments. For more help, contact your internet service provider.

Why is my Gmail not sending emails with attachments on Android?

Some temporary files stored in the Cache may be keeping your email from getting sent. Simply go to Settings>Privacy and Security and clear the cache and cookies. This is one of the best ways to fix the 'Can't Send Emails With Attachments From Gmail Account' issue.


4 Answers

I was able to pass a screenshot .jpeg file from my app to GMail 5.0 through an Intent. The key was in this answer.

Everything I have from @natasky 's code is nearly identical but instead, I have the file's directory as

context.getExternalCacheDir();

Which "represents the external storage directory where you should save cache files" (documentation)

like image 69
c0deblooded Avatar answered Oct 21 '22 10:10

c0deblooded


GMail 5.0 added some security checks to attachments it receives from an Intent. These are unrelated to unix permissions, so the fact that the file is readable doesn't matter.

When the attachment Uri is a file://, it'll only accept files from external storage, the private directory of gmail itself, or world-readable files from the private data directory of the calling app.

The problem with this security check is that it relies on gmail being able to find the caller app, which is only reliable when the caller has asked for result. In your code above, you do not ask for result and therefore gmail does not know who the caller is, and rejects your file.

Since it worked for you in 4.9 but not in 5.0, you know it's not a unix permission problem, so the reason must be the new checks.

TL;DR answer: replace startActivity with startActivityForResult.

Or better yet, use a content provider.

like image 40
Andro Id Avatar answered Oct 21 '22 09:10

Andro Id


Use getExternalCacheDir() with File.createTempFile.

Use the following to create a temporary file in the external cache directory:

File tempFile = File.createTempFile("fileName", ".txt", context.getExternalCacheDir());

Then copy your original file's content to tempFile,

FileWriter fw = new FileWriter(tempFile);

FileReader fr = new FileReader(Data.ERR_BAK_FILE);
int c = fr.read();
while (c != -1) {
    fw.write(c);
    c = fr.read();
}
fr.close();

fw.flush();
fw.close();

now put your file to intent,

emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(tempFile));
like image 18
Joshua Pinter Avatar answered Oct 21 '22 10:10

Joshua Pinter


You should implement a FileProvider, which can create Uris for your app's internal files. Other apps are granted permission to read these Uris. Then, simply instead of calling Uri.fromFile(attachment), you instantiate your FileProvider and use:

fileProvider.getUriForFile(attachment);
like image 5
Miloš Černilovský Avatar answered Oct 21 '22 10:10

Miloš Černilovský