JavaMail API 功能強大但底層 API 繁瑣。本文遞進展示:簡單文本 → 多收件人/抄送/密送 → 附件 → HTML 郵件 → 封裝配置類 → 批量發送複用 Session 框架,構建生產級郵件發送工具箱。
Session session = Session.getDefaultInstance(props, authenticator);
MimeMessage msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(from));
msg.addRecipient(TO, new InternetAddress(to));
msg.setSubject("Subject");
msg.setText("Content");
Transport.send(msg);
msg.addRecipients(TO, addresses);
msg.addRecipients(CC, addresses);
msg.addRecipients(BCC, addresses); // 密送,其他收件人不可見
MimeBodyPart textPart = new MimeBodyPart();
textPart.setText("Body");
MimeBodyPart attachPart = new MimeBodyPart();
attachPart.attachFile(new File("report.pdf"));
attachPart.setFileName(MimeUtility.encodeText("報告.pdf")); // 中文文件名編碼
MimeMultipart mp = new MimeMultipart();
mp.addBodyPart(textPart);
mp.addBodyPart(attachPart);
msg.setContent(mp);
MimeBodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent("Hello
", "text/html;charset=utf-8");
MimeMultipart mp = new MimeMultipart();
mp.addBodyPart(htmlPart);
msg.setContent(mp);
public class MailSenderConfig {
private String smtpHost, username, password, from, subject, content, contentType = "text/html;charset=utf-8";
private List to = new ArrayList<>(), cc = new ArrayList<>(), bcc = new ArrayList<>();
private List attachments = new ArrayList<>();
// 鏈式添加
public MailSenderConfig addTo(String mail) { to.add(mail); return this; }
public MailSenderConfig addAttachment(Attachment a) { attachments.add(a); return this; }
// ... getter/setter
}
public class Attachment {
private File file;
private String filename; // 可選,默認文件名
}
Session。MailSenderConfig 映射為 MimeMessage。getMessage()/setMessage() 允許高級定制。Transport.send(message)。public class MailSender {
private final MailSenderConfig config;
private MimeMessage message;
private Session session; // 可外部注入復用
public MailSender(MailSenderConfig config) { this(config, null); }
public MailSender(MailSenderConfig config, Session session) {
this.config = config; this.session = session; buildMessage();
}
private void buildMessage() {
if (session == null) session = createSession(config);
message = new MimeMessage(session);
// 設置 From/To/CC/BCC/Subject
// 構建 Multipart:文本/HTML + 附件
// 附件文件名用 MimeUtility.encodeText 避免中文亂碼
}
public void send() { Transport.send(message); }
public MimeMessage getMessage() { return message; }
public void setMessage(MimeMessage m) { this.message = m; }
public static Session createSession(MailSenderConfig c) { ... }
}
痛點:循環調用 new MailSender(config).send() 每次創建 Session+TCP 連接,性能極差。
方案:外部創建一次 Session,注入所有 MailSender 實例。
Session shared = MailSender.createSession(config);
for (User u : users) {
MailSenderConfig c = baseConfig.clone();
c.setSubject("專屬優惠 " + u.getName());
c.addTo(u.getEmail());
new MailSender(c, shared).send(); // 復用 Session
}
注意:Session 非線程安全,多線程批量發送需線程池 + ThreadLocal Session或每線程一 Session。
| 維度 | 措施 |
|---|---|
| 異步化 | 發送任務提交線程池/消息隊列,Controller 秒級返回 |
| 模板引擎 | Thymeleaf/Freemarker 渲染 HTML,分離業務與視圖 |
| 重試策略 | 指數退避 + 最大重試次數,失敗入死信隊列人工介入 |
| 發信信譽 | SPF/DKIM/DMARC 配置、頻率控制、退訂鏈接、黑名單過濾 |
| 監控告警 | 發送成功率、延遲、拒收率大盤,異常即時告警 |
| 安全 | 密碼加密存儲、TLS 必啟用、附件掃毒 |
從 MimeMessage 手工拼裝到 MailSenderConfig + MailSender 框架,核心演進是配置與發送分離、Session 復用、異步非阻塞。掌握 JavaMail 核心協議(SMTP/SMTPS/STARTTLS)、Mime 結構、中文編碼處理,才能構建穩健高效的郵件系統。