JavaMail API 是 Java 平台上處理電子郵件的標準擴展套件,提供了平台無關、協議無關的郵件收發框架。其核心設計遵循「關注點分離」原則,將郵件處理劃分為三大功能模組:
javax.mail.Message 及其子類 MimeMessage 是郵件內容的核心抽象。每個實例代表一封完整的電子郵件,封裝了發件人、收件人、主題、正文及附件等元素。MimeMessage 支援 MIME 標準,可處理多部分內容、編碼轉換及國際化字符集。
javax.mail.Transport 負責郵件發送,實現了 SMTP、SMTPAUTH 等協議。透過 Transport.send() 靜態方法或實例化 Transport 對象後調用 connect()、sendMessage(),即可完成郵件投遞。
javax.mail.Store 提供郵件接收功能,支援 POP3、IMAP 等協議。開發者可透過 Store 連接郵箱伺服器,獲取 Folder 對象進而讀取、搜尋、刪除郵件。
Session 類集中管理郵件會話的環境配置,包括:
Session 採用工廠模式創建 Transport、Store 和 Message 對象,確保配置一致性。可透過 Session.getInstance(props) 或 Session.getDefaultInstance(props) 獲取實例。
public class SimpleMailSender {
public static void main(String[] args) throws Exception {
Properties props = new Properties();
props.put("mail.host", "smtp.example.com");
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.port", "587");
props.put("mail.smtp.starttls.enable", "true");
Session session = Session.getInstance(props);
session.setDebug(true);
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("sender@example.com"));
message.setRecipient(Message.RecipientType.TO, new InternetAddress("recipient@example.com"));
message.setSubject("測試郵件", "UTF-8");
MimeBodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent("<h1>你好,JavaMail!</h1>", "text/html;charset=UTF-8");
MimeMultipart multipart = new MimeMultipart();
multipart.addBodyPart(htmlPart);
message.setContent(multipart);
message.saveChanges();
try (Transport transport = session.getTransport()) {
transport.connect("username", "password");
transport.sendMessage(message, message.getAllRecipients());
}
}
}
關鍵在於使用 cid: 協議引用內嵌資源,並將 MimeMultipart 子類型設為 related:
MimeBodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent("<img src='cid:logo.png'>", "text/html;charset=UTF-8");
MimeBodyPart imagePart = new MimeBodyPart();
imagePart.attachFile(new File("logo.png"));
imagePart.setContentID("<logo.png>");
MimeMultipart related = new MimeMultipart("related");
related.addBodyPart(htmlPart);
related.addBodyPart(imagePart);
message.setContent(related);
採用巢狀 MimeMultipart 結構:外層 mixed 包含內層 related(正文+圖片)與附件部分:
MimeMultipart mixed = new MimeMultipart("mixed");
// 內層:正文與圖片
MimeBodyPart contentPart = new MimeBodyPart();
contentPart.setContent(related); // 上方建立的 related multipart
mixed.addBodyPart(contentPart);
// 附件部分
MimeBodyPart attachment = new MimeBodyPart();
attachment.attachFile(new File("report.pdf"));
attachment.setFileName(MimeUtility.encodeText("報告.pdf"));
mixed.addBodyPart(attachment);
message.setContent(mixed);
javax.mail.Session 搭配連接池(如 Apache Commons Pool)複用 SMTP 連接。CompletableFuture 或消息隊列(RabbitMQ/Kafka)實現非阻塞郵件投遞。| 現象 | 可能原因 | 解決方向 |
|---|---|---|
| 535 Authentication failed | 帳號/密碼錯誤、未開啟 SMTP 服務、需應用專用密碼 | 檢查郵箱設置、生成應用專用密碼 |
| Connection timed out | 防火牆攔截、端口錯誤、網絡不通 | telnet 測試連通性、確認端口(465/587/25) |
| 中文亂碼 | 編碼未統一為 UTF-8 | 所有 setContent/setSubject 指定 charset、JVM 設置 -Dfile.encoding=UTF-8 |
| 大附件發送失敗 | 超過伺服器大小限制 | 分片上傳至雲存儲、郵件僅發送下載鏈接 |
JavaMail API 雖然歷經歲月,但憑藉其標準化設計與靈活擴展性,仍是 Java 生態中處理郵件業務的首選方案。掌握其核心模型與實戰模式,能讓你輕松應對從簡單通知到複雜營銷郵件的各種場景。