首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JavaMail 發送帶圖片內嵌與附件的 MIME 郵件完整實現

     編輯:Java 相關知識

JavaMail 多部分 MIME 郵件構建指南:內嵌圖片 + 多附件 + HTML 富文本

企業級郵件通知常需同時支援 HTML 排版、內嵌圖片 (CID 引用)、多格式附件。本文基於 Jakarta Mail (原 JavaMail) 實現完整的多層次 MIME 結構構建器。

MIME 多層次結構設計

multipart/mixed (最外層:混合容器)
├── multipart/related (關聯容器:HTML + 內嵌資源)
│   ├── text/html (HTML 正文,含 )
│   └── image/jpeg (內嵌圖片,Content-ID: <logo>)
├── application/pdf (附件 1,Content-Disposition: attachment)
└── application/octet-stream (附件 2,Content-Disposition: attachment)

核心三步驟實現

1. 構建 HTML 正文 + 內嵌圖片 (related)

public MimeBodyPart buildHtmlWithInlineImage(String html, String imagePath) throws MessagingException {
    MimeBodyPart htmlPart = new MimeBodyPart();
    htmlPart.setContent(html, "text/html; charset=utf-8");
    
    MimeBodyPart imagePart = new MimeBodyPart();
    DataSource fds = new FileDataSource(imagePath);
    imagePart.setDataHandler(new DataHandler(fds));
    imagePart.setHeader("Content-ID", "<logo>"); // 必須包含尖括號
    imagePart.setDisposition(MimeBodyPart.INLINE);
    
    MimeMultipart related = new MimeMultipart("related");
    related.addBodyPart(htmlPart);
    related.addBodyPart(imagePart);
    
    MimeBodyPart contentPart = new MimeBodyPart();
    contentPart.setContent(related);
    return contentPart;
}

2. 構建附件部分

public MimeBodyPart buildAttachment(String filePath) throws MessagingException {
    MimeBodyPart attachment = new MimeBodyPart();
    DataSource fds = new FileDataSource(filePath);
    attachment.setDataHandler(new DataHandler(fds));
    // MimeUtility.encodeText 解決中文文件名編碼問題
    attachment.setFileName(MimeUtility.encodeText(fds.getName(), "utf-8", "B"));
    attachment.setDisposition(MimeBodyPart.ATTACHMENT);
    return attachment;
}

3. 組裝最終郵件

public MimeMessage createMimeMessage(Session session, MailConfig config) throws MessagingException {
    MimeMessage msg = new MimeMessage(session);
    msg.setFrom(new InternetAddress(config.from, config.fromName, "utf-8"));
    msg.setRecipients(Message.RecipientType.TO, parseAddresses(config.to));
    msg.setSubject(config.subject, "utf-8");
    msg.setSentDate(new Date());
    
    // 最外層 mixed 容器
    MimeMultipart mixed = new MimeMultipart("mixed");
    
    // 1. 添加 HTML+圖片關聯部分
    mixed.addBodyPart(buildHtmlWithInlineImage(config.html, config.inlineImagePath));
    
    // 2. 添加多個附件
    for (String path : config.attachments) {
        mixed.addBodyPart(buildAttachment(path));
    }
    
    msg.setContent(mixed);
    msg.saveChanges(); // 重要:生成 Message-ID 等頭部
    return msg;
}

發送配置與優化

// SMTP 會話配置
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.exmail.qq.com");
props.put("mail.smtp.port", "465");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.ssl.enable", "true"); // SSL 直連
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.put("mail.debug", "false");

Session session = Session.getInstance(props, new Authenticator() {
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(username, authCode); // 授權碼非登錄密碼
    }
});

// 發送
Transport.send(message); // 或 Transport.send(message, addresses) 指定收件人

關鍵坑點避雷

問題解決方案
中文附件名亂碼`MimeUtility.encodeText(name, "utf-8", "B")` (B=Base64, Q=Quoted-Printable)
內嵌圖片不顯示Content-ID 必須含尖括號 ``,HTML 引用 `cid:logo` (無尖括號)
大附件發送超時調大 `mail.smtp.connectiontimeout`/`timeout`,或分片上傳雲存儲發鏈接
SSL/TLS 握手失敗JDK 8+ 需導入郵件服務器證書到 cacerts,或信任所有 (測試用)
群發性能差使用 `Transport.sendMessage(msg, allAddresses)` 單連接發送,或異步隊列

HTML 模板最佳實踐

<html>
<body style="font-family: 'Microsoft YaHei', sans-serif;">
  <div style="border:1px solid #ddd; padding:20px; max-width:600px;">
    <h2>訂單確認通知</h2>
    <p>親愛的 ${userName},您的訂單 <strong>${orderNo}</strong> 已確認。</p>
    <img src="cid:logo" alt="公司Logo" style="max-width:150px;">
    <table>...訂單明細...</table>
  </div>
</body>
</html>

建議使用 Thymeleaf/FreeMarker 渲染模板,分離業務邏輯與視圖。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved