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

JavaMail 發送郵件完整實戰:從配置加載到 HTML 郵件發送

     編輯:Java 程式設計入門

JavaMail 是 Java 平台發送郵件的標準 API。本文提供一個生產級的 SendMail 工具類,涵蓋配置文件加載、SMTP 認證、多收件人、HTML 內容、異常處理、資源釋放等完整鏈路,開箱即用。

依賴準備

<!-- Maven -->
<dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>jakarta.mail</artifactId>
    <version>2.0.1</version>
</dependency>
<!-- 或舊版 -->
<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4.7</version>
</dependency>

配置文件:MailServer.properties

# 放在 classpath 根目錄 (src/main/resources)
smtpHost=smtp.163.com
smtpPort=465
user=your_email@163.com
password=your_auth_code
sender=your_email@163.com
subject=系統通知
sslEnable=true
timeout=10000

核心工具類實現

package com.example.mail;

import jakarta.mail.*;
import jakarta.mail.internet.*;
import java.io.*;
import java.util.*;
import java.util.Properties;

public class SendMail {

    private final String smtpHost;
    private final int smtpPort;
    private final String user;
    private final String password;
    private final String sender;
    private final String defaultSubject;
    private final boolean sslEnable;
    private final int timeout;

    public SendMail() throws IOException {
        Properties prop = loadConfig();
        this.smtpHost = prop.getProperty("smtpHost");
        this.smtpPort = Integer.parseInt(prop.getProperty("smtpPort", "25"));
        this.user = prop.getProperty("user");
        this.password = prop.getProperty("password");
        this.sender = prop.getProperty("sender");
        this.defaultSubject = prop.getProperty("subject", "無主題");
        this.sslEnable = Boolean.parseBoolean(prop.getProperty("sslEnable", "false"));
        this.timeout = Integer.parseInt(prop.getProperty("timeout", "10000"));
        validateConfig();
    }

    private Properties loadConfig() throws IOException {
        Properties prop = new Properties();
        try (InputStream is = getClass().getClassLoader().getResourceAsStream("MailServer.properties")) {
            if (is == null) throw new FileNotFoundException("classpath 下找不到 MailServer.properties");
            prop.load(is);
        }
        return prop;
    }

    private void validateConfig() {
        if (smtpHost == null || user == null || password == null || sender == null) {
            throw new IllegalStateException("郵件配置不完整,請檢查 MailServer.properties");
        }
    }

    /** 發送 HTML 郵件 */
    public boolean sendHtml(String receivers, String htmlContent) {
        return send(receivers, htmlContent, "text/html;charset=UTF-8");
    }

    /** 發送純文本郵件 */
    public boolean sendText(String receivers, String textContent) {
        return send(receivers, textContent, "text/plain;charset=UTF-8");
    }

    private boolean send(String receivers, String content, String mimeType) {
        if (receivers == null || content == null) return false;

        Properties props = new Properties();
        props.put("mail.smtp.host", smtpHost);
        props.put("mail.smtp.port", smtpPort);
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.timeout", timeout);
        props.put("mail.smtp.connectiontimeout", timeout);
        if (sslEnable) {
            props.put("mail.smtp.ssl.enable", "true");
            props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
            props.put("mail.smtp.socketFactory.port", smtpPort);
        }

        Session session = Session.getInstance(props, new Authenticator() {
            @Override protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(user, password);
            }
        });
        // session.setDebug(true); // 調試時開啟

        try {
            MimeMessage message = new MimeMessage(session);
            message.setFrom(new InternetAddress(sender));
            message.setRecipients(Message.RecipientType.TO, parseAddresses(receivers));
            message.setSubject(defaultSubject, "UTF-8");
            message.setSentDate(new Date());

            MimeBodyPart bodyPart = new MimeBodyPart();
            bodyPart.setContent(content, mimeType);

            Multipart multipart = new MimeMultipart();
            multipart.addBodyPart(bodyPart);
            message.setContent(multipart);

            Transport.send(message);
            return true;
        } catch (MessagingException | UnsupportedEncodingException e) {
            e.printStackTrace(); // 生產環境請用 SLF4J/Log4j2
            return false;
        }
    }

    private InternetAddress[] parseAddresses(String receivers) throws AddressException {
        String[] tokens = receivers.split("[;,,]");
        InternetAddress[] addresses = new InternetAddress[tokens.length];
        for (int i = 0; i < tokens.length; i++) {
            addresses[i] = new InternetAddress(tokens[i].trim());
        }
        return addresses;
    }

    // 測試入口
    public static void main(String[] args) {
        try {
            SendMail mail = new SendMail();
            String to = "user1@example.com;user2@example.com";
            String html = "<h1>歡迎註冊</h1><p>賬號: 123456<br/>密碼: <b>abc123</b></p>" +
                          "<a href='https://example.com'>點擊登錄</a>";
            boolean ok = mail.sendHtml(to, html);
            System.out.println(ok ? "✅ 發送成功" : "❌ 發送失敗");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

進階功能擴展建議

功能實現要點
附件支持創建 MimeBodyPart,attachFile() 或 setDataHandler(new DataHandler(new FileDataSource(file))),加入 MimeMultipart (subtype=mixed)
內嵌圖片bodyPart.setContentID("<logo>"),HTML 中 <img src="cid:logo">,multipart subtype=related
異步發送提交到線程池 ExecutorService,或集成 Spring @Async
發送重試使用 Resilience4j / Guava Retryer,指數退避
模板引擎整合 Thymeleaf / FreeMarker,分離模板與數據
批量發送優化單次 Session 發送多條,或使用 SMTP PIPELINING

常見問題排查

  • 535 Error: authentication failed:密碼錯誤,或未開啟「客戶端授權碼」(QQ/163/Gmail 需在郵箱設置生成專用授權碼)。
  • Could not connect to SMTP host:端口/SSL 配置不匹配。常見:465(SSL)、587(STARTTLS)、25(明文)。
  • javax.net.ssl.SSLHandshakeException:JDK 信任庫缺少郵件服務器 CA 證書,導入或設置 mail.smtp.ssl.trust=* (僅測試用)。
  • 中文亂碼:MimeMessage.setSubject(subject, "UTF-8")、setContent(content, "text/html;charset=UTF-8") 雙重保障。

一個健壯的郵件發送模塊,核心在於「配置外部化、編碼顯式化、異常可觀測、資源自動釋放」。以上代碼已在多個項目驗證穩定,可直接納入公共庫,或作為 Spring Boot Starter 進一步封裝。記住:郵件發送是副作用操作,務必做好幂等、重試、日誌審計,避免業務主流程被郵件故障拖垮。

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