Skip to content

Java 发送电子邮件

从 Java 应用程序发送电子邮件需要使用 Jakarta Mail API(以前称为 JavaMail)。这个 API 提供了类来使用标准协议(如 SMTP、POP3 和 IMAP)编写、发送和接收电子邮件。

要使用 Jakarta Mail API,你需要将它的依赖项包含在你的项目中。管理依赖项的现代方式是使用构建工具,例如 Maven 或 Gradle。

Maven 依赖 (pom.xml):

<dependencies>
<!-- Jakarta Mail API -->
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>jakarta.mail</artifactId>
<version>2.0.1</version> <!-- 使用最新版本 -->
</dependency>
<!-- Jakarta Activation API (Jakarta Mail 所需) -->
<!-- 使用 Angus 提供的运行时依赖 -->
<dependency>
<groupId>org.eclipse.angus</groupId>
<artifactId>angus-activation</artifactId>
<version>2.0.1</version> <!-- 使用最新版本 -->
</dependency>
</dependencies>

Gradle 依赖 (build.gradle):

dependencies {
// Jakarta Mail API
implementation 'com.sun.mail:jakarta.mail:2.0.1' // 使用最新版本
// Jakarta Activation API (Jakarta Mail 所需)
// 使用 Angus 提供的运行时依赖
implementation 'org.eclipse.angus:angus-activation:2.0.1' // 使用最新版本
}

确保你使用的是兼容且最新的这些库版本。

要发送电子邮件,你需要使用你的邮件服务器的属性(SMTP 主机、端口、认证详细信息)配置一个 Session 对象。

**重要:**对于实际应用,避免在代码中直接硬编码凭证。使用配置文件、环境变量或安全的凭证管理系统。

配置示例 (使用 Gmail 作为 SMTP 服务器):

import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
// ... 在你的类或方法内部 ...
final String username = "your_email@gmail.com"; // 你的 Gmail 地址
final String password = "your_app_password"; // 对 Gmail 使用应用专用密码,不要使用你的普通密码
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.gmail.com"); // Gmail SMTP 主机
props.put("mail.smtp.port", "587"); // TLS 端口
props.put("mail.smtp.auth", "true"); // 启用身份验证
props.put("mail.smtp.starttls.enable", "true"); // 启用 STARTTLS
// 创建带 Authenticator 的 Session 对象
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});

**关于 Gmail 应用专用密码的说明:**如果你使用 Gmail 并启用了两步验证,则必须为你的应用程序生成一个“应用专用密码”,而不是使用你的主要 Google 帐户密码。在 Google 帐户帮助中搜索“使用应用专用密码登录”。

配置好 Session 后,你可以创建并发送一个 MimeMessage。

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
// ... 其他导入,包括 Session, Properties 等 ...
public class SimpleEmailSender {
public static void main(String[] args) {
final String username = "your_email@gmail.com";
final String password = "your_app_password";
final String recipientEmail = "recipient@example.com";
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.gmail.com");
props.put("mail.smtp.port", "587");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
try {
// 创建新的电子邮件消息
Message message = new MimeMessage(session);
// 设置发件人
message.setFrom(new InternetAddress(username));
// 设置收件人
message.setRecipients(Message.RecipientType.TO,
InternetAddress.parse(recipientEmail));
// 设置主题
message.setSubject("Test Email from Java");
// 设置内容 (纯文本)
message.setText("Hello,\n\nThis is a simple test email sent from a Java application.");
// 发送消息
Transport.send(message);
System.out.println("电子邮件发送成功!");
} catch (MessagingException e) {
System.err.println("发送电子邮件出错:" + e.getMessage());
e.printStackTrace();
}
}
}

发送给多个收件人:

你可以使用逗号分隔的地址在 InternetAddress.parse() 中指定多个收件人,或者单独添加收件人。

// 多个 TO 收件人
message.setRecipients(Message.RecipientType.TO,
InternetAddress.parse("recipient1@example.com, recipient2@example.com"));
// 添加 CC 或 BCC 收件人
message.addRecipients(Message.RecipientType.CC,
InternetAddress.parse("cc_recipient@example.com"));
message.addRecipients(Message.RecipientType.BCC,
InternetAddress.parse("bcc_recipient@example.com"));

要发送 HTML 内容,请使用 setContent() 方法,并指定适当的 MIME 类型(“text/html”)。

// ... (会话设置同前) ...
try {
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(username));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipientEmail));
message.setSubject("HTML Test Email from Java");
// HTML 内容
String htmlContent = "<h1>Hello!</h1>"
+ "<p>This is an **HTML** email sent from Java.</p>"
+ "<p><a href='https://www.example.com'>Visit Example.com</a></p>";
// 将内容设置为 HTML
message.setContent(htmlContent, "text/html; charset=utf-8"); // 指定字符集
Transport.send(message);
System.out.println("HTML 电子邮件发送成功!");
} catch (MessagingException e) {
System.err.println("发送 HTML 电子邮件出错:" + e.getMessage());
e.printStackTrace();
}

指定字符编码(如 utf-8)在内容类型中是一种良好的实践。

发送附件涉及创建一个多部分消息 (MimeMultipart),其中包含不同的正文部分 (MimeBodyPart)——一个用于文本/HTML 正文,其他用于附件。

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.Multipart;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
// ... 其他导入 ...
// ... (会话设置同前) ...
try {
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(username));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipientEmail));
message.setSubject("Email with Attachment from Java");
// 1. 创建消息正文部分 (文本或 HTML)
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText("Hello,\n\nPlease find the attached file.");
// 或者对于 HTML: messageBodyPart.setContent(htmlContent, "text/html; charset=utf-8");
// 2. 创建一个多部分消息容器
Multipart multipart = new MimeMultipart();
// 将文本/HTML 部分添加到多部分容器
multipart.addBodyPart(messageBodyPart);
// 3. 创建附件部分
BodyPart attachmentBodyPart = new MimeBodyPart();
String filename = "path/to/your/file.txt"; // 指定你的文件的正确路径
DataSource source = new FileDataSource(filename);
attachmentBodyPart.setDataHandler(new DataHandler(source));
attachmentBodyPart.setFileName(source.getName()); // 使用 source.getName() 获取实际的文件名
// 将附件部分添加到多部分容器
multipart.addBodyPart(attachmentBodyPart);
// --- 如果需要,类似地添加更多附件 ---
// 4. 将多部分容器设置为消息内容
message.setContent(multipart);
// 5. 发送消息
Transport.send(message);
System.out.println("带附件的电子邮件发送成功!");
} catch (MessagingException e) {
System.err.println("发送带附件的电子邮件出错:" + e.getMessage());
e.printStackTrace();
} catch (Exception e) { // 捕获潜在的文件处理错误
System.err.println("访问附件文件出错:" + e.getMessage());
e.printStackTrace();
}

确保 filename 中的文件路径正确,并且应用程序有权限读取该文件。

  • **错误处理:**总是将发送邮件的代码包装在 try-catch 块中,以处理 MessagingException 和潜在的其他异常(如附件的 IO 异常)。适当地记录错误。
  • **凭证:**永远不要硬编码敏感凭证。使用安全的方法,例如环境变量、具有适当权限保护的配置文件或专用的秘密管理服务。
  • **异步发送:**对于需要响应性的应用程序(如 Web 应用程序),考虑使用单独的线程或消息队列异步发送电子邮件,以避免阻塞主应用程序线程。
  • **连接池:**对于高吞吐量的发送,如果你的邮件服务或基于 Jakarta Mail 构建的库提供连接池选项,请进行研究。
  • **速率限制:**注意电子邮件提供商(如 Gmail)施加的发送限制,以避免被封锁。
  • **电子邮件模板:**对于复杂的 HTML 电子邮件,使用模板引擎(如 Thymeleaf、Freemarker)将表示层与 Java 代码分离。
  • **资源管理:**尽管 Transport.send() 通常会处理关闭连接,但如果你直接管理 Transport 对象,请确保它们在 finally 块中关闭,或者如果适用则使用 try-with-resources。