Question

At first you're going to think "Wait, this question is a duplicate!". Read on.

I'm trying to use the Intent ACTION_SENDTO (with an Email URI as data) in order to have just email apps respond.

(Using ACTION_SEND launches a standard "SEND" chooser with no data URI meaning that non email apps, such as Google Drive, also respond).

My problem is that the attachment works with ACTION_SEND on all devices, however - when using ACTION_SENDTO only some devices correctly attach the files. Nexus 7 works but Samsung Galaxy Tab and Acer Iconia don't.

You can see below the different methods side by side:

    String email    = getActivity().getResources().getString(R.string.supportEmail);
    String subject  = getActivity().getResources().getString(R.string.sFeedback);
    subject         = String.format(subject, 
                      getActivity().getResources().getString(R.string.productName));
    String content  = getActivity().getResources().getString(R.string.whatFeedbackWouldYouLikeToProvide) + "\n\n" + 
                      mMessage.getText().toString();
    File toSend     = new File(outfile);

    if(toSend.exists()) {
        Log.e("Feedback", "File path: " + toSend.getAbsolutePath());

        Intent emailIntent = new Intent(android.content.Intent.ACTION_SENDTO);
        emailIntent.setData(Uri.parse("mailto:" +email));
        emailIntent.putExtra(android.content.Intent.EXTRA_STREAM,   Uri.fromFile(toSend));
        emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT,  subject);               
        emailIntent.putExtra(android.content.Intent.EXTRA_TEXT,     content);  

    /*  Intent emailIntent = new Intent(Intent.ACTION_SEND);
        emailIntent.setType("message/rfc822");
        emailIntent.putExtra(Intent.EXTRA_EMAIL  , new String[]{email});
        emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
        emailIntent.putExtra(Intent.EXTRA_TEXT   , content);
        emailIntent.putExtra(Intent.EXTRA_STREAM , Uri.fromFile(toSend)); */

        try {
            startActivity(emailIntent);
        } catch (ActivityNotFoundException anfe) {
            Toast.makeText(getActivity(), getResources().getString(R.string.pleaseInstallAnEmailClientInOrderToSendUsFeedback), 8000).show();
        }
    }

You can see that the filepaths don't seem to be the problem, I've added in some logging which reports:

Samsung Gives:

04-11 11:40:09.953: E/Feedback(6286): File path: /storage/sdcard0/logs.zip

Nexus Gives:

04-11 11:38:59.249: E/Feedback(12702): File path: /storage/emulated/0/logs.zip

(Both based on getExternalStorageDirectory() to ensure cross application access).

Does anybody know why the difference?

Was it helpful?

Solution 2

Try to resolve activity via ACTION_SENDTO, but actually sending via ACTION_SEND.

Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts(
                    "mailto", "", null));
            intent.putExtra(Intent.EXTRA_SUBJECT, title);
            intent.putExtra(Intent.EXTRA_TEXT, text);
            intent.putExtra(Intent.EXTRA_STREAM, getSnapshotUri(snapshot, context, event));

            List<ResolveInfo> resolveInfos = context.getPackageManager().queryIntentActivities(intent, 0);
            if (resolveInfos.size() == 0) {
                new AlertDialog.Builder(context)
                        .setMessage(R.string.no_mail_app)
                        .setPositiveButton(R.string.ok, null)
                        .show();
            } else {
                String packageName = resolveInfos.get(0).activityInfo.packageName;
                String name = resolveInfos.get(0).activityInfo.name;

                intent.setAction(Intent.ACTION_SEND);
                intent.setComponent(new ComponentName(packageName, name));

                context.startActivity(intent);
            }

OTHER TIPS

The only solution I came up with is the following one. It is a mix of some others I have found while searching for a complete answer. The following will show only email apps and allow including attachments. The most important part was found here: https://stackoverflow.com/a/8550043/4927659

ArrayList<Uri> uris = new ArrayList<>();
uris.add(Uri.parse("file://" + filepath)); 
//filepath is something like that: /mnt/sdcard/DCIM/DSC0001.JPG
Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts(
                "mailto", "example@gmail.com", null));
        emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Mail subject");
        List<ResolveInfo> resolveInfos = getPackageManager().queryIntentActivities(emailIntent, 0);
        List<LabeledIntent> intents = new ArrayList<>();
        for (ResolveInfo info : resolveInfos) {
            Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
            intent.setComponent(new ComponentName(info.activityInfo.packageName, info.activityInfo.name));
            intent.putExtra(Intent.EXTRA_EMAIL, new String[]{"example@gmail.com"});
            intent.putExtra(Intent.EXTRA_SUBJECT, "Mail subject");
            intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); //ArrayList<Uri> of attachment Uri's
            intents.add(new LabeledIntent(intent, info.activityInfo.packageName, info.loadLabel(getPackageManager()), info.icon));
        }
        Intent chooser = Intent.createChooser(intents.remove(intents.size() - 1), "Send email with attachments...");
        chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents.toArray(new LabeledIntent[intents.size()]));
        startActivity(chooser);

I encountered the similiar problem and was scratching my head all day, until I found a potential answer on a Chinese blog: http://flysnow.iteye.com/blog/1128354

Nearly to the end of the article, it talks about the intent filters that Android's built-in email client has:

<activity
    android:name=".activity.MessageCompose"
    android:label="@string/app_name"
    android:enabled="false">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <action android:name="android.intent.action.SENDTO" />
        <data android:scheme="mailto" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
    </intent-filter>
    <intent-filter android:label="@string/app_name">
        <action android:name="android.intent.action.SEND" />
        <data android:mimeType="text/plain" />
        <data android:mimeType="image/*" />
        <data android:mimeType="video/*" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

You can see it has two intent filters to handle SEND and SENDTO intents differently, and only SEND is specified with mimeType. The code snippet was way back to Android 1.6 but it hasn't been changed much. You can find it in the recent version:

https://android.googlesource.com/platform/packages/apps/Email/+/f44b729bff619d0a9f0b1492726351e41c1e5d5d/AndroidManifest.xml

I'm not sure why they don't specify mimeType in SENDTO intent, but that's the way it is, I think most email client probably doing the same way (except for Gmail, it can successfully attach file when using SENDTO intent). Could that also be your case? Therefore, to be safe you should only send attachment using the SEND intent.

you could try putting the subject and body in the Uri. This question seems to imply that might resolve the problem.

The thing is Intent.ACTION_SEND is handled by different email clients correctly even if recepient is specified (that is incorrect, but..). So one must use this action if wants to support other clients than Gmail. That is just how it works.

And to add recepient just add exactly the same line you'd add if were using Intent.ACTION_SENDTO:

Intent emailIntent = new Intent(Intent.ACTION_SEND);
String mailto = "abc@def.com";
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{mailTo});
...

In my case file attachment was not added in clients other than Gmail with Intent.ACTION_SENDTO and switching to Intent.ACTION_SEND solved it.

After a lot of trying and combining, this is the version I use to send multiple attachments only in an email apps:

public static void sendMailWithAttachedFiles(Context activityContext, ArrayList<String> filePaths, String MAIL, String SUBJECT, String TEXT) {
    ArrayList<Uri> uris = new ArrayList<>();
    for (String filePath : filePaths) {
        File file = new File(filePath);

        Uri csvUri = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            csvUri = FileProvider.getUriForFile(activityContext, activityContext.getPackageName() + ".provider", file);
        } else {
            //doesn't work in API 24+
            csvUri  =   Uri.fromFile(file);
        }

        uris.add(csvUri);
    }

    Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", MAIL, null));
    emailIntent.putExtra(Intent.EXTRA_SUBJECT, SUBJECT);
    emailIntent.putExtra(Intent.EXTRA_TEXT, TEXT);


    List<ResolveInfo> resolveInfos = activityContext.getPackageManager().queryIntentActivities(emailIntent, 0);
    List<LabeledIntent> intents = new ArrayList<>();
    for (ResolveInfo info : resolveInfos) {
        Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
        intent.setComponent(new ComponentName(info.activityInfo.packageName, info.activityInfo.name));
        intent.putExtra(Intent.EXTRA_EMAIL, new String[]{MAIL});
        intent.putExtra(Intent.EXTRA_SUBJECT, SUBJECT);
        intent.putExtra(Intent.EXTRA_TEXT, TEXT);
        intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
        intents.add(new LabeledIntent(intent, info.activityInfo.packageName, info.loadLabel(activityContext.getPackageManager()), info.icon));
    }
    Intent chooser = Intent.createChooser(intents.remove(intents.size() - 1), "Send email using");
    chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents.toArray(new LabeledIntent[intents.size()]));
    activityContext.startActivity(chooser);
}

in Manifest:

    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="${applicationId}.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths" />
    </provider>

Create xml folder in res folder and add this file provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path name="external_files" path="."/>
</paths>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top