1. 概述

本文将介绍如何使用 Java 核心邮件库发送邮件,包括带附件和不带附件的场景。我们将通过实际代码演示关键操作,帮助开发者快速掌握邮件发送功能。

2. 项目设置与依赖

我们使用基于 Maven 的项目,并引入 Angus Mail 作为依赖。这是 Jakarta Mail API 规范的 Eclipse 实现:

<dependency>
    <groupId>org.eclipse.angus</groupId>
    <artifactId>angus-mail</artifactId>
    <version>2.0.1</version>
</dependency>

最新版本可在 Maven 仓库 查询。

3. 发送纯文本与 HTML 邮件

首先需要配置邮件服务提供商的凭据,然后创建用于构建邮件的 Session 对象。配置通过 Java Properties 对象完成:

Properties prop = new Properties();
prop.put("mail.smtp.auth", true);
prop.put("mail.smtp.starttls.enable", "true");
prop.put("mail.smtp.host", "sandbox.smtp.mailtrap.io");
prop.put("mail.smtp.port", "25");
prop.put("mail.smtp.ssl.trust", "sandbox.smtp.mailtrap.io");

⚠️ 注意:以上配置使用了 Mailtrap 的测试服务。实际使用时需根据服务商文档调整主机地址(不同 SMTP 集成方式主机可能不同)。

接下来使用用户名密码创建会话:

Session session = Session.getInstance(prop, new Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication("your_username", "your_password");
    }
});

现在创建邮件消息并发送:

Message message = new MimeMessage(session);
message.setFrom(new InternetAddress("[email protected]"));
message.setRecipients(
  Message.RecipientType.TO, InternetAddress.parse("[email protected]"));
message.setSubject("邮件主题");

String msg = "这是使用 JavaMailer 发送的第一封邮件";

MimeBodyPart mimeBodyPart = new MimeBodyPart();
mimeBodyPart.setContent(msg, "text/html; charset=utf-8");

Multipart multipart = new MimeMultipart();
multipart.addBodyPart(mimeBodyPart);

message.setContent(multipart);

Transport.send(message);

核心逻辑说明:

  1. 创建消息对象并设置发件人、收件人、主题
  2. 创建 MimeBodyPart 存储正文(使用 HTML 编码)
  3. MimeMultipart 包装正文部分
  4. multipart 设置为消息内容并发送

关键点: MimeBodyPart 被包含在消息的 multipart 中,而一个 multipart 可以包含多个 MimeBodyPart(下一节将利用此特性添加附件)。

4. 发送带附件的邮件

添加附件只需创建额外的 MimeBodyPart 并附加文件:

MimeBodyPart attachmentBodyPart = new MimeBodyPart();
attachmentBodyPart.attachFile(new File("path/to/file"));

然后将新部件添加到之前创建的 MimeMultipart 对象:

multipart.addBodyPart(attachmentBodyPart);

就这么简单! 最后设置 multipart 为消息内容并调用 send() 发送邮件即可。

5. 格式化邮件文本

使用 HTML 和 CSS 标签可美化邮件内容。例如:

  • 使用 <b> 标签加粗文本
  • 通过 style 属性设置颜色
  • 组合 HTML 与 CSS 实现复杂样式

示例代码(创建红色粗体文本):

String msgStyled = "这是我的 <b style='color:red;'>红色粗体邮件</b> 使用 JavaMailer";

此字符串将作为邮件正文发送。

6. 发送邮件给多个收件人

使用 setRecipients()addRecipients() 方法可设置多个收件人,支持 TOCCBCC 类型。

6.1. 使用 setRecipients()

通过收件人数组设置:

Address[] recipients = new InternetAddress[2];
recipients[0] = new InternetAddress("[email protected]");
recipients[1] = new InternetAddress("[email protected]");

message.setRecipients(Message.RecipientType.TO, recipients);

或使用 InternetAddress.parse() 解析 CSV 格式地址:

message.setRecipients(Message.RecipientType.TO, 
    InternetAddress.parse("[email protected], [email protected]"));

6.2. 使用 addRecipients()

setRecipients() 的区别:

  • setRecipients() 会覆盖已有收件人列表
  • addRecipients() 在现有列表基础上追加

示例(追加收件人):

Address[] newRecipients = new InternetAddress[2]; 
newRecipients[0] = new InternetAddress("[email protected]"); 
newRecipients[1] = new InternetAddress("[email protected]");

message.addRecipients(Message.RecipientType.TO, newRecipients);

同样支持 CSV 解析:

message.addRecipients(Message.RecipientType.TO, 
    InternetAddress.parse("[email protected], [email protected]"));

7. 设置连接超时

处理邮件服务时需防范网络问题,特别是服务器响应慢或不可达的情况。通过以下属性配置超时:

prop.put("mail.smtp.connectiontimeout", "10000");  // 连接超时(毫秒)
prop.put("mail.smtp.timeout", "10000");           // 读取超时
prop.put("mail.smtp.writetimeout", "10000");      // 写入超时

超时参数说明:

  • mail.smtp.connectiontimeout:建立 SMTP 连接的等待时间
  • mail.smtp.timeout:从服务器读取数据的等待时间
  • mail.smtp.writetimeout:向服务器写入数据的等待时间

设置后,当 SMTP 服务器无响应时应用不会无限期挂起。

8. 忽略服务器证书错误

开发环境中遇到自签名证书或测试证书时,可通过以下配置跳过证书验证:

prop.put("mail.smtp.ssl.trust", "*");               // 信任所有证书
prop.put("mail.smtp.ssl.checkserveridentity", false); // 禁用服务器身份检查

对于 SMTPS 协议,仅设置 mail.smtp.ssl.trust="*" 可能不够,需自定义 SSLSocketFactory

// 创建信任所有证书的 TrustManager
TrustManager[] trustAllCerts = new TrustManager[]{
    new X509TrustManager() {
        public void checkClientTrusted(X509Certificate[] certs, String authType) {}
        public void checkServerTrusted(X509Certificate[] certs, String authType) {}
        public X509Certificate[] getAcceptedIssuers() { 
            return new X509Certificate[0];
        }
    }
};

// 初始化 SSL 上下文
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

// 设置自定义 Socket Factory
props.put("mail.smtp.ssl.enable", "true");
props.put("mail.smtp.ssl.socketFactory", sslSocketFactory);
props.put("mail.smtp.ssl.trust", "*");

⚠️ 重要提示: 此方法完全禁用证书验证,仅限测试环境使用。生产环境必须使用受信任 CA 颁发的有效 SSL 证书确保通信安全。

9. 总结

本文演示了使用 Jakarta Mail API 发送邮件的核心功能:

  • ✅ 发送纯文本/HTML 邮件
  • ✅ 添加附件
  • ✅ 格式化邮件内容
  • ✅ 发送给多个收件人
  • ✅ 配置连接超时
  • ✅ 处理开发环境证书问题

通过合理配置 Properties 和组合 MimeBodyPart,可灵活实现各种邮件发送需求。生产环境中需特别注意证书安全性和超时配置。


原始标题:Sending Emails with Java | Baeldung