【问题标题】:Sending email with attachment using SENDTO on some devices doesn't work在某些设备上使用 SENDTO 发送带附件的电子邮件不起作用
【发布时间】:2013-04-03 12:02:03
【问题描述】:

一开始你会想“等等,这个问题是重复的!”。继续阅读。

我正在尝试使用 Intent ACTION_SENDTO(以电子邮件 URI 作为数据)以便只是电子邮件应用程序响应。

(使用ACTION_SEND 启动标准的“SEND”选择器,没有数据 URI,这意味着非电子邮件应用程序(例如 Google Drive)也会响应)。

我的问题是附件适用于所有设备上的ACTION_SEND,但是 - 当使用ACTION_SENDTO 时,只有一些设备正确附加文件。 Nexus 7 可以工作,但三星 Galaxy Tab 和 Acer Iconia不能

您可以在下面并排查看不同的方法:

    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();
        }
    }

您可以看到文件路径似乎不是问题,我在一些记录中添加了报告:

三星给予:

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

Nexus 给予:

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

(均基于getExternalStorageDirectory()保证跨应用访问)。

有人知道为什么会这样吗?

【问题讨论】:

  • 应该是Uri.parse("mailto:" + email),但您在该行还缺少一个括号,因此可能是问题错字。
  • 是的,抱歉,有问题。
  • filePath 中一定有问题,因为其余代码是正确的。只需交叉检查 URI 是否引用有效位置。其次,需要附加的文件不能在应用程序目录或缓存目录中。
  • 查看已编辑的问题 - 如您所见,我添加了对现有文件的检查(以及记录绝对路径以确保其位于可行的位置)
  • 你解决过这个问题吗?

标签: android sendto


【解决方案1】:

我想出的唯一解决方案是以下一个。这是我在寻找完整答案时发现的其他一些内容的混合体。以下将仅显示电子邮件应用程序并允许包含附件。最重要的部分在这里找到: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);

【讨论】:

  • 嗨,我想出了类似的解决方案。太丑了,无法通过 SENDTO 发送该附件。
  • 非常好的解决方案!我将完成这个答案,在for 循环之后添加一个if 块以避免在未找到邮件客户端时出现错误:if (intents.size() &gt; 0)
【解决方案2】:

尝试通过 ACTION_SENDTO 解决活动,但实际上是通过 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);
            }

【讨论】:

  • 仍然希望用户可以选择哪个电子邮件客户端,但这无疑是解决这个问题的一个很好的开始,而且非常聪明 - 如果我回到这个问题,我会尝试对此进行改进。谢谢!
  • 我使用以下解决活动:intent.resolveActivity(getPackageManager());
  • 这个答案的问题:它任意使用从queryIntentActivities返回的第一个活动
  • 您可以遍历 resolveInfos 并找到合适的活动。
【解决方案3】:

我遇到了类似的问题,整天摸不着头脑,直到我在中文博客上找到了可能的答案:http://flysnow.iteye.com/blog/1128354

在文章的最后,它谈到了 Android 内置电子邮件客户端所具有的意图过滤器:

<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>

您可以看到它有两个意图过滤器来不同地处理 SEND 和 SENDTO 意图,并且只有 SEND 使用 mimeType 指定。代码 sn-p 可以追溯到 Android 1.6,但没有太大变化。您可以在最新版本中找到它:

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

我不确定他们为什么不在 SENDTO 意图中指定 mimeType,但事实就是这样,我认为大多数电子邮件客户端可能都是这样做的(Gmail 除外,它可以在使用 SENDTO 意图时成功附加文件)。你的情况可能也是这样吗?因此,为了安全起见,您应该只使用 SEND 意图发送附件。

【讨论】:

    【解决方案4】:

    您可以尝试将主体和主体放在 Uri 中。 This question 似乎暗示这可能会解决问题。

    【讨论】:

    • 不 - 没什么区别(代码看起来更丑) - 文件仍然没有被包含 :) 感谢您的尝试!
    • stackoverflow.com/a/1279574 所建议的emailIntent.putExtra(android.content.Intent.EXTRA_STREAM, Uri.parse("file://"+ toSend)); 怎么样
    【解决方案5】:

    问题是Intent.ACTION_SEND 由不同的电子邮件客户端正确处理,即使指定了收件人(这是不正确的,但是..)。因此,如果想要支持 Gmail 以外的其他客户端,则必须使用此操作。这就是它的工作原理。

    要添加收件人,只需添加与使用 Intent.ACTION_SENDTO 时添加的完全相同的行:

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

    在我的情况下,文件附件没有添加到 Gmail 以外的客户端中,Intent.ACTION_SENDTO 并切换到 Intent.ACTION_SEND 解决了这个问题。

    【讨论】:

      【解决方案6】:

      经过大量尝试和组合,这是我仅用于在电子邮件应用中发送多个附件的版本:

      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);
      }
      

      在清单中:

          <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>
      

      在 res 文件夹中创建 xml 文件夹并添加此文件 provider_paths.xml

      <?xml version="1.0" encoding="utf-8"?>
      <paths>
          <external-path name="external_files" path="."/>
      </paths>
      

      【讨论】:

        猜你喜欢
        • 2016-01-24
        • 2015-06-06
        • 1970-01-01
        • 2014-04-23
        • 2016-10-23
        • 2012-01-15
        • 1970-01-01
        • 1970-01-01
        • 2022-12-17
        相关资源
        最近更新 更多