如何仅使用电子邮件应用程序发送带附件的电子邮件?

Posted

技术标签:

【中文标题】如何仅使用电子邮件应用程序发送带附件的电子邮件?【英文标题】:How to send Email with attachment using only email apps? 【发布时间】:2016-09-08 01:33:37 【问题描述】:

有两个要求:

带附件的电子邮件 在Intent 选择器中,应该只有电子邮件应用程序。

我知道/做过的事:

Intent.ACTION_SENDTOintent.setData(Uri.parse("mailto:")) 可以确保Intent 选择器中只有电子邮件应用程序,但它不会带附件(对于某些应用程序,例如 Gmail,它会,但也有很多应用程序会忽略附件)。

Intent.ACTION_SEND 可以发送带有附件的电子邮件。但是,在Intent 选择器中,会有一些应用程序实际上不是电子邮件应用程序,但可以响应Intent.ACTION_SEND。使用intent.setType("message/rfc822") 可以减少这些应用的数量,但不是全部。

参考这个答案:https://***.com/a/8550043/3952691 并且几乎成功实现了我的目标。我的代码如下:

private static void sendFeedbackWithAttachment(Context context, String subject) 
    Intent intent = new Intent(Intent.ACTION_SENDTO);
    intent.setData(Uri.parse("mailto:"));

    PackageManager packageManager = context.getPackageManager();
    List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent, 0);
    if (resolveInfos.isEmpty()) 
        Toast.makeText(context, context.getString(R.string.error_activity_not_found),
                Toast.LENGTH_SHORT).show();
     else 
        // ACTION_SEND may be replied by some apps that are not email apps. However,
        // ACTION_SENDTO doesn't allow us to choose attachment. As a result, we use
        // an ACTION_SENDTO intent with email data to filter email apps and then send
        // email with attachment by ACTION_SEND.
        List<LabeledIntent> intents = new ArrayList<>();
        Uri uri = getLatestLogUri();
        for (ResolveInfo info : resolveInfos) 
            Intent i = new Intent(Intent.ACTION_SEND);
            i.setPackage(info.activityInfo.packageName);
            i.setClassName(info.activityInfo.packageName, info.activityInfo.name);
            i.putExtra(Intent.EXTRA_EMAIL, new String[]  Def.Meta.FEEDBACK_EMAIL );
            i.putExtra(Intent.EXTRA_SUBJECT, subject);
            i.putExtra(Intent.EXTRA_STREAM, uri);
            intents.add(new LabeledIntent(i, info.activityInfo.packageName,
                    info.loadLabel(context.getPackageManager()), info.icon));
        
        Intent chooser = Intent.createChooser(intents.remove(0),
                context.getString(R.string.send_feedback_to_developer));
        chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS,
                intents.toArray(new LabeledIntent[intents.size()]));
        context.startActivity(chooser);
    

但是在某些设备上(比如小米2S和MIUI V5,不知道会不会受到第三方rom的影响),结果是一个空的Intent选择器。而且似乎在android 6.0以上,Intent.EXTRA_INITIAL_INTENTS有一些bug(Custom intent-chooser - why on Android 6 does it show empty cells?,还有一个:https://code.google.com/p/android/issues/detail?id=202693)。

因此,我不知道如何实现我的目标。请帮助我,提前谢谢你。

【问题讨论】:

"Intent.ACTION_SENDTO 和 intent.setData(Uri.parse("mailto:")) 可以确保 Intent 选择器中只有电子邮件应用程序" -- 不,它没有。它将选择支持Intent 结构的任何应用程序放入选择器中。任何人都可以编写这样的应用程序,它可能不是“电子邮件应用程序”。没有关于“电子邮件应用程序”是什么的通用声明。 @CommonsWare 是的,我知道。但我说的是普通情况。我们可以说,一个应用程序具有IntentFilter for Intent.ACTION_SEND 和数据方案为“mailto”,如果它是一个正式应用程序,它应该具有处理电子邮件事件的能力,因此我们可以将其视为“电子邮件应用程序” "。 @ywwynm 使用 .setType("message/rfc822") 或选择器将向您显示所有(许多)支持发送意图的应用程序。 @Stanojkovic 你能仔细看看我的问题描述吗?在“我所知道/做过的事情”部分,我说我尝试使用“message/rfc822”,但它不符合我的需求。 @ywwynm 这就是我管理发送邮件的方式:String mailTo = "email@gmail.com";Intent email_intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", mailTo, null)); 【参考方案1】:

试试下面的代码发送邮件

String filename="filename.vcf"; 
File filelocation = new File(Environment.getExternalStorageDirectory().getAbsolutePath(), filename);
Uri path = Uri.fromFile(filelocation); 
Intent emailIntent = new Intent(Intent.ACTION_SEND);
// set the type to 'email'
emailIntent .setType("vnd.android.cursor.dir/email");
String to[] = "asd@gmail.com";
emailIntent .putExtra(Intent.EXTRA_EMAIL, to);
// the attachment
emailIntent .putExtra(Intent.EXTRA_STREAM, path);
// the mail subject
emailIntent .putExtra(Intent.EXTRA_SUBJECT, "Subject");
startActivity(Intent.createChooser(emailIntent , "Send email..."));

【讨论】:

message/rfc822怎么样,是不是设置了邮件类型?【参考方案2】:

有两种方法可以做到这一点

选项 1

 Intent emailIntent = new Intent(
            android.content.Intent.ACTION_VIEW);

     
     //Option 1
    Uri data = Uri.parse("mailto:?subject=" + "blah blah subject"
            + "&body=" + "blah blah body" + "&to=" + "sendme@me.com");
    emailIntent.setData(data);

    startActivity(Intent.createChooser(emailIntent, ""));

结果

选项 2

除了不会过滤掉 FTP 之外,它可以正常工作

    //Option 2
  emailIntent = new Intent(
            android.content.Intent.ACTION_SEND);
    emailIntent.setType("message/rfc822");
    final String[] toRecipients = new String[]  "sendme@me.com", "", ;
    emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, toRecipients);
    emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "blah blah subject");
    emailIntent.putExtra(android.content.Intent.EXTRA_TEXT,
            html.fromHtml("blah blah body"));

    startActivity(Intent.createChooser(emailIntent, ""));

结果

两种方式都有小缺陷我向你展示了两种方式,现在由你来选择一个。

【讨论】:

以上是关于如何仅使用电子邮件应用程序发送带附件的电子邮件?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 InputStream 和 Spring 发送带附件的电子邮件?

Python向多人发送、抄送带附件的邮件(含详细代码)

python - 发送带各种类型附件的邮件

在 gmail android 应用程序中发送带附件的电子邮件时出错

用Python实现带附件发送邮件的功能

用Python实现带附件发送邮件的功能