javax.mail:mail:1.4.7 / com.sun.mail:jakarta.mail:2.0.1 (Jakarta EE 9+)| 類/接口 | 作用 |
|---|---|
Session | 郵件會話上下文,持有屬性 (SMTP 主機、認證、調試等),單例模式 |
Message / MimeMessage | 郵件模型,包含發件人、收件人、主題、內容、發送時間 |
Transport | 發送協議實現 (SMTP),connect()、sendMessage() |
MimeMultipart | MIME 多部分容器,組合文本、附件、內嵌圖片 |
MimeBodyPart | 單個 MIME 部分:文本體或附件體 |
DataSource / FileDataSource | 附件數據源 |
public class MailSender {
// --- 配置屬性 ---
private String host; // SMTP 服務器
private String from; // 發件人
private String to; // 收件人 (可擴展為 List)
private String username; // SMTP 認證用戶
private String password; // SMTP 認證密碼
private String subject; // 主題
private String textContent; // 純文本/HTML 內容
private List<File> attachments; // 附件文件列表
// --- 構建器模式簡化調用 ---
public static Builder builder() { return new Builder(); }
public void send() throws MessagingException {
Properties props = new Properties();
props.put("mail.smtp.host", host);
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.port", "25"); // 或 465/587 (SSL/TLS)
// SSL 配置示例
// props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
// props.put("mail.smtp.socketFactory.port", "465");
Session session = Session.getInstance(props, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
session.setDebug(true); // 開發期開啟調試
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to));
message.setSubject(subject, "UTF-8");
// --- 構建多部分內容 ---
Multipart multipart = new MimeMultipart("mixed"); // mixed: 附件+文本並列
// 1. 文本/HTML 部分
MimeBodyPart textPart = new MimeBodyPart();
textPart.setContent(textContent, "text/html; charset=UTF-8"); // 支持 HTML
multipart.addBodyPart(textPart);
// 2. 附件部分
if (attachments != null) {
for (File file : attachments) {
MimeBodyPart attachPart = new MimeBodyPart();
attachPart.setDataHandler(new DataHandler(new FileDataSource(file)));
// 關鍵:MimeUtility.encodeWord 解決中文附件名亂碼 (RFC 2047)
attachPart.setFileName(MimeUtility.encodeWord(file.getName(), "UTF-8", null));
multipart.addBodyPart(attachPart);
}
}
message.setContent(multipart);
message.saveChanges(); // 重要:生成 Message-ID、Date 等頭部
// --- 發送 ---
try (Transport transport = session.getTransport("smtp")) {
transport.connect(host, username, password);
transport.sendMessage(message, message.getAllRecipients());
}
}
// --- Builder 內部類 ---
public static class Builder {
private final MailSender sender = new MailSender();
public Builder host(String h) { sender.host = h; return this; }
public Builder from(String f) { sender.from = f; return this; }
public Builder to(String t) { sender.to = t; return this; }
public Builder auth(String u, String p) { sender.username = u; sender.password = p; return this; }
public Builder subject(String s) { sender.subject = s; return this; }
public Builder htmlContent(String html) { sender.textContent = html; return this; }
public Builder attachments(List<File> files) { sender.attachments = files; return this; }
public MailSender build() { return sender; }
}
}
MailSender.builder()
.host("smtp.exmail.qq.com")
.from("sender@domain.com")
.to("receiver@domain.com")
.auth("sender@domain.com", "password")
.subject("測試郵件 - 帶附件與 HTML")
.htmlContent("<h1>你好</h1><p>這是<b>HTML</b>郵件</p><img src='cid:logo'/>")
.attachments(Arrays.asList(new File("report.pdf"), new File("logo.png")))
.build()
.send();
附件 Part 設置 Content-ID 頭:
MimeBodyPart imgPart = new MimeBodyPart();
imgPart.setDataHandler(new DataHandler(new FileDataSource("logo.png")));
imgPart.setHeader("Content-ID", "<logo>"); // 帶尖括號
imgPart.setDisposition(MimeBodyPart.INLINE); // 內聯顯示
multipart.addBodyPart(imgPart);
HTML 中引用:<img src="cid:logo" /> (cid: 後接 Content-ID 去掉尖括號)。
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); props.put("mail.smtp.port", "465");props.put("mail.smtp.starttls.enable", "true"); props.put("mail.smtp.port", "587");Session 與 Transport 連接。ExecutorService) 避免阻塞主線程。BCC 隱藏地址,或分批發送防反垃圾攔截。| 異常 | 原因 | 對策 |
|---|---|---|
AuthenticationFailedException | 用戶名/密碼錯誤、未開啟 SMTP 服務、需授權碼 | 驗證郵箱設置,使用客戶端授權碼而非登錄密碼 |
MessagingException: Could not connect to SMTP host | 主機/端口錯誤、防火牆攔截、SSL/TLS 配置不匹配 | telnet 測試端口連通性,確認 SSL 模式 |
UnsupportedEncodingException | 附件名/主題包含非 ASCII 字符未編碼 | 統一使用 MimeUtility.encodeWord(text, "UTF-8", null) |