<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.5</version>
</dependency>
<!-- 間接依賴:jakarta.mail (JavaMail API 實現) -->
Mailpublic class Mail implements Serializable {
private String host; // SMTP 服務器
private String sender; // 發件人郵箱
private String senderName; // 發件人顯示名
private String username; // 登錄用戶名
private String password; // 登錄密碼/授權碼
private String subject; // 主題
private String htmlContent; // HTML 正文
private List<String> to; // 收件人列表
private List<String> cc; // 抄送
private List<String> bcc; // 密送
private List<FileItem> attachments; // 附件
// getter/setter 省略
public static class FileItem {
private File file;
private String fileName;
private String mimeType;
// constructor/getter/setter
}
}
MailUtilpublic class MailUtil {
private static final Logger LOG = LoggerFactory.getLogger(MailUtil.class);
private static final String CHARSET = "UTF-8";
public boolean send(Mail mail) {
HtmlEmail email = new HtmlEmail();
try {
// 1. 基礎配置
email.setHostName(mail.getHost());
email.setCharset(CHARSET);
email.setSSLOnConnect(true); // 大多數 SMTP 需 SSL
email.setSslSmtpPort("465"); // SSL 端口
email.setAuthentication(mail.getUsername(), mail.getPassword());
email.setFrom(mail.getSender(), mail.getSenderName());
// 2. 收件人
for (String addr : mail.getTo()) email.addTo(addr);
for (String addr : mail.getCc()) email.addCc(addr);
for (String addr : mail.getBcc()) email.addBcc(addr);
// 3. 內容
email.setSubject(mail.getSubject());
email.setHtmlMsg(mail.getHtmlContent()); // 支援 HTML
email.setTextMsg("您的郵件客戶端不支援 HTML,請查看網頁版。"); // 純文本備選
// 4. 附件
if (mail.getAttachments() != null) {
for (Mail.FileItem item : mail.getAttachments()) {
EmailAttachment att = new EmailAttachment();
att.setPath(item.getFile().getAbsolutePath());
att.setDisposition(EmailAttachment.ATTACHMENT);
att.setDescription(item.getFileName());
att.setName(item.getFileName());
email.attach(att);
}
}
// 5. 發送
email.send();
LOG.info("郵件發送成功:{} -> {}", mail.getSender(), mail.getTo());
return true;
} catch (Exception e) {
LOG.error("郵件發送失敗", e);
return false;
}
}
}
@Test
void sendHtmlMail() {
Mail mail = new Mail();
mail.setHost("smtp.qq.com"); // 或 smtp.163.com, smtp.gmail.com
mail.setSender("your@qq.com");
mail.setSenderName("測試發送者");
mail.setUsername("your@qq.com");
mail.setPassword("授權碼"); // 非登錄密碼,需在郵箱開啟 SMTP 獲取
mail.setTo(List.of("target@example.com"));
mail.setCc(List.of("cc@example.com"));
mail.setSubject("Commons Email HTML 測試");
mail.setHtmlContent("""
<!DOCTYPE html>
<html><body>
<h1 style="color:#2c3e50">HTML 郵件測試</h1>
<p>支援 <strong>粗體</strong>、<a href="https://example.com">鏈接</a>、圖片</p>
<img src="cid:logo" alt="Logo"/>
</body></html>
""");
// 內嵌圖片需用 cid 引用,Commons Email 需額外處理,此處略
assertTrue(new MailUtil().send(mail));
}
| 問題 | 原因 | 解決 |
|---|---|---|
| 535 Error: authentication failed | 密碼錯誤/未開啟 SMTP/用登錄密碼而非授權碼 | 郵箱設置中開啟 SMTP,生成授權碼填入 password |
| Connection timeout | 端口/主機錯誤、防火牆、網絡不通 | 檢查 465/587 端口,telnet 測試連通性 |
| 中文亂碼 | 編碼未統一 | setCharset("UTF-8"),主題/正文/附件名均用 UTF-8 |
| 大附件發送失敗 | 郵箱限制單郵件大小(通常 20-50MB) | 分卷壓縮、雲盤分享鏈接、或分多封發送 |
@Async + 線程池異步發送,避免阻塞主線程。setHtmlMsg()。email.embed(new File("logo.png"), "logo"),HTML 中用 <img src="cid:logo">。Commons Email 封裝了 JavaMail 底層細節,提供鏈式 API 發送 HTML/附件/抄送郵件,配合異步與模板引擎即可滿足企業級郵件發送需求。