Java 发送电子邮件
Java - 发送电子邮件
Section titled “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' // 使用最新版本}确保你使用的是兼容且最新的这些库版本。
配置邮件会话
Section titled “配置邮件会话”要发送电子邮件,你需要使用你的邮件服务器的属性(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 帐户帮助中搜索“使用应用专用密码登录”。
发送简单文本电子邮件
Section titled “发送简单文本电子邮件”配置好 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 电子邮件
Section titled “发送 HTML 电子邮件”要发送 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)在内容类型中是一种良好的实践。
发送带附件的电子邮件
Section titled “发送带附件的电子邮件”发送附件涉及创建一个多部分消息 (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 中的文件路径正确,并且应用程序有权限读取该文件。
错误处理与最佳实践
Section titled “错误处理与最佳实践”- **错误处理:**总是将发送邮件的代码包装在
try-catch块中,以处理MessagingException和潜在的其他异常(如附件的 IO 异常)。适当地记录错误。 - **凭证:**永远不要硬编码敏感凭证。使用安全的方法,例如环境变量、具有适当权限保护的配置文件或专用的秘密管理服务。
- **异步发送:**对于需要响应性的应用程序(如 Web 应用程序),考虑使用单独的线程或消息队列异步发送电子邮件,以避免阻塞主应用程序线程。
- **连接池:**对于高吞吐量的发送,如果你的邮件服务或基于 Jakarta Mail 构建的库提供连接池选项,请进行研究。
- **速率限制:**注意电子邮件提供商(如 Gmail)施加的发送限制,以避免被封锁。
- **电子邮件模板:**对于复杂的 HTML 电子邮件,使用模板引擎(如 Thymeleaf、Freemarker)将表示层与 Java 代码分离。
- **资源管理:**尽管
Transport.send()通常会处理关闭连接,但如果你直接管理Transport对象,请确保它们在finally块中关闭,或者如果适用则使用 try-with-resources。