關鍵配置:mail.smtp.auth=true 需授權碼而非登錄密碼;session.setDebug(true) 開啟調試輸出。
Properties props = new Properties();
props.setProperty("mail.transport.protocol", "smtp");
props.setProperty("mail.host", "smtp.163.com");
props.setProperty("mail.smtp.auth", "true");
Session session = Session.getInstance(props);
session.setDebug(true);
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("xxx@163.com"));
message.setRecipients(Message.RecipientType.TO, "xxx@qq.com");
message.setSubject("測試郵件");
// HTML內容
message.setContent("<h1>Hello JavaMail</h1>", "text/html;charset=UTF-8");
// 純文本備選
// message.setText("純文本內容");
message.saveChanges();
Transport ts = session.getTransport();
ts.connect("xxx@163.com", "授權碼"); // 注意:此處為授權碼
ts.sendMessage(message, message.getAllRecipients());
要點:setContent(String, "text/html") 支持富文本;saveChanges() 更新頭部字段(如Message-ID、Date)。
關鍵模型:multipart/related 關聯文本與圖片,圖片通過 Content-ID (cid:) 引用。
// 文本部分
MimeBodyPart textPart = new MimeBodyPart();
textPart.setContent("正文內容<img src='cid:imageId'>繼續正文", "text/html;charset=UTF-8");
// 圖片部分
MimeBodyPart imagePart = new MimeBodyPart();
imagePart.setContentID("<imageId>"); // 需包含<>
DataHandler dh = new DataHandler(new FileDataSource("src/logo.png"));
imagePart.setDataHandler(dh);
// 關聯容器
MimeMultipart relatedMp = new MimeMultipart();
relatedMp.addBodyPart(textPart);
relatedMp.addBodyPart(imagePart);
relatedMp.setSubType("related"); // 關鍵:related
message.setContent(relatedMp);
坑點提示:setContentID 值需與HTML中cid:後的標識一致,建議加角括號<id>提高兼容性;需引入JAF (activation.jar) 支持DataHandler。
分層結構:multipart/mixed (頂層) → [附件Part, multipart/related (文本+圖片)]
// 文本+圖片 關聯層(同上)
MimeMultipart relatedMp = new MimeMultipart();
relatedMp.addBodyPart(textPart);
relatedMp.addBodyPart(imagePart);
relatedMp.setSubType("related");
// 包裝為單一Part
MimeBodyPart textImagePart = new MimeBodyPart();
textImagePart.setContent(relatedMp);
// 附件部分
MimeBodyPart attachPart = new MimeBodyPart();
DataHandler attachDh = new DataHandler(new FileDataSource("src/報表.pdf"));
attachPart.setDataHandler(attachDh);
// 解決中文附件名亂碼
attachPart.setFileName(MimeUtility.encodeText(attachDh.getName()));
// 最終混合容器
MimeMultipart mixedMp = new MimeMultipart();
mixedMp.addBodyPart(attachPart); // 附件通常在前
mixedMp.addBodyPart(textImagePart); // 正文在後
mixedMp.setSubType("mixed");
message.setContent(mixedMp);
編碼關鍵:MimeUtility.encodeText(filename) 實現RFC 2047編碼,解決中文附件名在各郵箱客戶端顯示亂碼問題。
| 現象 | 可能原因 | 解決方案 |
|---|---|---|
| 發送失敗 535 Error | 授權碼錯誤/未開啟SMTP服務 | 郵箱設定中生成專用授權碼,開啟SMTP/IMAP |
| 圖片不顯示 | cid不匹配 / Content-ID格式錯誤 | 確保setContentID(" |
| 附件名亂碼 | 未編碼 / 編碼方式不兼容 | 使用MimeUtility.encodeText() 或 MimeUtility.encodeWord() |
| 進垃圾箱 | 內容關鍵詞 / 發信域信譽 | 配置SPF/DKIM/DMARC,優化內容,避免營銷詞彙 |
JavaMail通過MimeMultipart嵌套組合實現複雜郵件結構:related綁定文本與內嵌資源,mixed混合附件與正文。掌握「容器套容器、Part裝Part」的組合模式,配合正確MIME類型與編碼處理,即可構建企業級郵件發送能力。