Sending email with attachment using SENDTO on some

2020-06-04 03:56发布

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?

5条回答
爷、活的狠高调
2楼-- · 2020-06-04 04:14

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);
            }
查看更多
小情绪 Triste *
3楼-- · 2020-06-04 04:20

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

查看更多
看我几分像从前
4楼-- · 2020-06-04 04:21

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.

查看更多
贼婆χ
5楼-- · 2020-06-04 04:34

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.

查看更多
我欲成王,谁敢阻挡
6楼-- · 2020-06-04 04:37

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);
查看更多
登录 后发表回答