我正在开发一个应用程序在Android。我不知道如何从应用程序发送电子邮件?


当前回答

我在我的应用程序中使用下面的代码。这显示准确的电子邮件客户端应用程序,如Gmail。

    Intent contactIntent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", getString(R.string.email_to), null));
    contactIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.email_subject));
    startActivity(Intent.createChooser(contactIntent, getString(R.string.email_chooser)));

其他回答

为了让电子邮件应用程序来解决你的意图,你需要指定ACTION_SENDTO作为动作和mailto作为数据。

private void sendEmail(){

    Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
    emailIntent.setData(Uri.parse("mailto:" + "recipient@example.com")); // You can use "mailto:" if you don't know the address beforehand.
    emailIntent.putExtra(Intent.EXTRA_SUBJECT, "My email's subject");
    emailIntent.putExtra(Intent.EXTRA_TEXT, "My email's body");
    
    try {
        startActivity(Intent.createChooser(emailIntent, "Send email using..."));
    } catch (android.content.ActivityNotFoundException ex) {
        Toast.makeText(Activity.this, "No email clients installed.", Toast.LENGTH_SHORT).show();
    }

}

解决方案很简单:android文档解释了这一点。

(https://developer.android.com/guide/components/intents-common.html邮件)

最重要的是标志:它是ACTION_SENDTO,而不是ACTION_SEND

另一条重要的线是

intent.setData(Uri.parse("mailto:")); ***// only email apps should handle this***

顺便说一下,如果你发送一个空的Extra,末尾的if()将不起作用,应用程序将无法启动电子邮件客户端。

根据Android文档。如果你想确保你的意图只被电子邮件应用程序处理(而不是其他短信或社交应用程序),那么使用ACTION_SENDTO动作并包括“mailto:”数据方案。例如:

public void composeEmail(String[] addresses, String subject) {
    Intent intent = new Intent(Intent.ACTION_SENDTO);
    intent.setData(Uri.parse("mailto:")); // only email apps should handle this
    intent.putExtra(Intent.EXTRA_EMAIL, addresses);
    intent.putExtra(Intent.EXTRA_SUBJECT, subject);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivity(intent);
    }
}

发送电子邮件可以用intent完成,不需要配置。但这样就需要用户交互,布局也会受到一些限制。

在没有用户交互的情况下构建和发送更复杂的电子邮件需要构建自己的客户端。第一件事是用于电子邮件的Sun Java API不可用。我曾经成功地利用Apache Mime4j库来构建电子邮件。都是基于nilvec的文件。

使用. settype ("message/rfc822")或ACTION_SEND的策略似乎也适用于非电子邮件客户端的应用程序,如Android Beam和蓝牙。

使用ACTION_SENDTO和mailto: URI似乎工作得很好,并且在开发人员文档中推荐使用。但是,如果你在官方模拟器上这样做,并且没有设置任何电子邮件帐户(或者没有任何邮件客户端),你会得到以下错误:

不支持的操作 目前不支持该操作。

如下图所示:

结果是模拟器将意图解析为一个名为com.android.fallback的活动。Fallback,它显示上面的消息。显然这是故意的。

如果你想让你的应用在官方模拟器上也能正常运行,你可以在发送邮件之前检查一下:

private void sendEmail() {
    Intent intent = new Intent(Intent.ACTION_SENDTO)
        .setData(new Uri.Builder().scheme("mailto").build())
        .putExtra(Intent.EXTRA_EMAIL, new String[]{ "John Smith <johnsmith@yourdomain.com>" })
        .putExtra(Intent.EXTRA_SUBJECT, "Email subject")
        .putExtra(Intent.EXTRA_TEXT, "Email body")
    ;

    ComponentName emailApp = intent.resolveActivity(getPackageManager());
    ComponentName unsupportedAction = ComponentName.unflattenFromString("com.android.fallback/.Fallback");
    if (emailApp != null && !emailApp.equals(unsupportedAction))
        try {
            // Needed to customise the chooser dialog title since it might default to "Share with"
            // Note that the chooser will still be skipped if only one app is matched
            Intent chooser = Intent.createChooser(intent, "Send email with");
            startActivity(chooser);
            return;
        }
        catch (ActivityNotFoundException ignored) {
        }

    Toast
        .makeText(this, "Couldn't find an email app and account", Toast.LENGTH_LONG)
        .show();
}

在开发人员文档中找到更多信息。

筛选“真正的”电子邮件应用程序在今天仍然是一个问题。正如上面许多人提到的,现在其他应用程序也报告支持mime类型的“message/rfc822”。因此,这种mime类型不再适合用于真正的电子邮件应用程序的过滤。

如果你想发送一个简单的文本邮件,使用ACTION_SENDTO意图动作和适当的数据类型就足够了,如下所示:

Intent intent = new Intent(Intent.ACTION_SENDTO);
intent.setData(Uri.parse("mailto:"));
intent.putExtra(Intent.EXTRA_EMAIL, recipients);
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.putExtra(Intent.EXTRA_TEXT, text);
Intent chooser = Intent.createChooser(intent, "Send Mail");
context.startActivity(chooser);

这将过滤所有支持“mailto”协议的应用程序,这更适合发送电子邮件。

但不幸的是,如果你想发送带有(多个)附件的邮件,事情就变得复杂了。ACTION_SENDTO动作不支持EXTRA_STREAM额外的意图。如果你想使用它,你必须使用ACTION_SEND_MULTIPLE动作,它不能与数据类型Uri.parse("mailto:")一起工作。

目前我找到了一个解决方案,具体步骤如下:

声明你的应用程序想要查询设备上支持mailto协议的应用程序(对Android 11以来的所有应用程序都很重要) 实际上查询所有支持mailto协议的应用程序 对于每个支持应用:构建你真正想要启动的意图,针对那个单一的应用 构建App选择器并启动它

这是它在代码中的样子:

添加到AndroidManifest:

<queries>
    <intent>
        <action android:name="android.intent.action.SENDTO" />
        <data android:scheme="mailto" />
    </intent>
</queries>

这是Java代码:

/* Query all Apps that support the 'mailto' protocol */
PackageManager pm = context.getPackageManager();
Intent emailCheckerIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"));
List<ResolveInfo> emailApps = pm.queryIntentActivities(emailCheckerIntent, PackageManager.MATCH_DEFAULT_ONLY);

/* For each supporting App: Build an intent with the desired values */
List<Intent> intentList = new ArrayList<>();
for (ResolveInfo resolveInfo : emailApps) {
    String packageName = resolveInfo.activityInfo.packageName;
    Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
    intent.setPackage(packageName);
    intent.setComponent(new ComponentName(packageName, resolveInfo.activityInfo.name));
    intent.putExtra(Intent.EXTRA_EMAIL, recipients);
    intent.putExtra(Intent.EXTRA_SUBJECT, subject);
    intent.putExtra(Intent.EXTRA_TEXT, text);
    intent.putExtra(Intent.EXTRA_STREAM, attachmentUris);
    intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //IMPORTANT to give the E-Mail App access to your attached files
                
    intentList.add(intent);
}

/* Create a chooser consisting of the queried apps only */
Intent chooser = Intent.createChooser(intentList.remove(intentList.size() - 1), "Send Mail");
Intent[] extraIntents = intentList.toArray(new Intent[0]);
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents);
context.startActivity(chooser);

注意:如果itentList只有一个项目,Android会自动跳过选择器并自动运行唯一的应用程序。