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

JavaMail 發送郵件完整實戰:從基礎文本到帶附件、HTML 富文本

     編輯:Java 相關知識

環境準備

  • JDK 1.6+ (內含 JavaMail API 1.4+)
  • 或手動添加依賴: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()
MimeMultipartMIME 多部分容器,組合文本、附件、內嵌圖片
MimeBodyPart單個 MIME 部分:文本體或附件體
DataSource / FileDataSource附件數據源

完整發送類:MailSender

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();

進階主題

1. 內嵌圖片 (HTML 中引用附件)

附件 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 去掉尖括號)。

2. SSL/TLS 安全發送

  • SMTPS (465 端口隱式 SSL):props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); props.put("mail.smtp.port", "465");
  • STARTTLS (587 端口顯式升級):props.put("mail.smtp.starttls.enable", "true"); props.put("mail.smtp.port", "587");

3. 批量發送優化

  • 復用 Session 與 Transport 連接。
  • 異步隊列 (如 ExecutorService) 避免阻塞主線程。
  • 大量收件人用 BCC 隱藏地址,或分批發送防反垃圾攔截。

4. 常見異常排查

異常原因對策
AuthenticationFailedException用戶名/密碼錯誤、未開啟 SMTP 服務、需授權碼驗證郵箱設置,使用客戶端授權碼而非登錄密碼
MessagingException: Could not connect to SMTP host主機/端口錯誤、防火牆攔截、SSL/TLS 配置不匹配telnet 測試端口連通性,確認 SSL 模式
UnsupportedEncodingException附件名/主題包含非 ASCII 字符未編碼統一使用 MimeUtility.encodeWord(text, "UTF-8", null)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved