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

JavaMail 發送郵件實戰:QQ 郵箱 SMTP 配置、認證授權碼與屬性文件外部化

     編輯:Java 程式設計入門

前置準備:QQ 郵箱開啟 SMTP 服務

代碼前必須在 QQ 郵箱網頁端完成設置:

  1. 登錄 QQ 郵箱 → 設置 → 賬戶
  2. 找到「POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV 服務」區域
  3. 開啟 SMTP 服務,會彈出驗證對話框,按提示發送短信驗證
  4. 驗證通過後,會生成一個 16 位授權碼(非 QQ 密碼!),務必妥善保存,僅顯示一次。

SMTP 服務器地址:smtp.qq.com,端口:465 (SSL) 或 587 (STARTTLS)。本文以 SSL 465 為例。

Maven 依賴


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

核心發送代碼(含 SSL 配置)


public class EmailSender {
    private final Session session;
    private final String from;

    public EmailSender(String username, String authCode) {
        this.from = username;
        Properties props = new Properties();
        props.put("mail.smtp.host", "smtp.qq.com");
        props.put("mail.smtp.port", "465");
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        props.put("mail.smtp.socketFactory.port", "465");
        props.put("mail.smtp.ssl.enable", "true"); // JDK 1.8+ 簡化配置
        
        // 認證器
        Authenticator auth = new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, authCode);
            }
        };
        this.session = Session.getInstance(props, auth);
    }

    public void sendHtmlEmail(String to, String subject, String htmlContent) throws MessagingException {
        MimeMessage message = new MimeMessage(session);
        message.setFrom(new InternetAddress(from));
        message.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
        message.setSubject(subject, "UTF-8");
        message.setSentDate(new Date());
        
        // 構建 MimeMultipart 支持 HTML + 附件擴展
        MimeMultipart multipart = new MimeMultipart();
        MimeBodyPart htmlPart = new MimeBodyPart();
        htmlPart.setContent(htmlContent, "text/html; charset=UTF-8");
        multipart.addBodyPart(htmlPart);
        
        message.setContent(multipart);
        Transport.send(message);
    }
}

配置外部化:Properties 文件管理敏感信息

email.properties(放在 `src/main/resources`,加入 `.gitignore`)


mail.host=smtp.qq.com
mail.port=465
mail.username=your_qq@qq.com
mail.authCode=xxxxxxxxxxxxxxxx  # 16位授權碼
mail.ssl.enable=true

配置加載工具類


public class EmailConfig {
    private static final Properties PROPS = new Properties();
    static {
        try (InputStream is = EmailConfig.class.getClassLoader().getResourceAsStream("email.properties")) {
            if (is == null) throw new IllegalStateException("email.properties not found in classpath");
            PROPS.load(is);
        } catch (IOException e) {
            throw new ExceptionInInitializerError(e);
        }
    }
    public static String get(String key) { return PROPS.getProperty(key); }
    public static int getInt(String key) { return Integer.parseInt(PROPS.getProperty(key)); }
}


發送器整合配置類


public class ConfiguredEmailSender {
    private final Session session;
    private final String from;

    public ConfiguredEmailSender() {
        this.from = EmailConfig.get("mail.username");
        Properties props = new Properties();
        props.put("mail.smtp.host", EmailConfig.get("mail.host"));
        props.put("mail.smtp.port", EmailConfig.get("mail.port"));
        props.put("mail.smtp.auth", "true");
        if (EmailConfig.get("mail.ssl.enable").equals("true")) {
            props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
            props.put("mail.smtp.socketFactory.port", EmailConfig.get("mail.port"));
            props.put("mail.smtp.ssl.enable", "true");
        }
        
        Authenticator auth = new Authenticator() {
            @Override protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(from, EmailConfig.get("mail.authCode"));
            }
        };
        this.session = Session.getInstance(props, auth);
    }
    // sendHtmlEmail 方法同上...
}

進階功能:附件、內嵌圖片、群發


// 添加附件
MimeBodyPart attachment = new MimeBodyPart();
attachment.attachFile(new File("report.pdf"));
multipart.addBodyPart(attachment);

// 內嵌圖片 (HTML 中用 )
MimeBodyPart imagePart = new MimeBodyPart();
imagePart.attachFile(new File("logo.png"));
imagePart.setContentID("<logoId>"); // CID
imagePart.setDisposition(MimeBodyPart.INLINE);
multipart.addBodyPart(imagePart);

// 群發 (BCC 隱藏收件人)
message.addRecipients(Message.RecipientType.BCC, InternetAddress.parse("a@qq.com, b@163.com"));

常見錯誤排查表

錯誤現象原因解決方案
535 Error: authentication failed授權碼錯誤/未開啟 SMTP重新生成授權碼,確認 SMTP 已開啟
Could not connect to SMTP host端口/協議不匹配/防火牆嘗試 587+STARTTLS,檢查網絡/代理
javax.net.ssl.SSLHandshakeExceptionJDK 版本/證書問題升級 JDK,或設置 `mail.smtp.ssl.trust=*`(不推薦生產)
中文附件名亂碼RFC 2231 編碼缺失`MimeUtility.encodeText(filename)` 設置文件名
發送超時網絡延遲/大附件設置 `mail.smtp.connectiontimeout`/`timeout`,異步發送

生產級建議:異步發送與重試


@Async("emailExecutor")
@Retryable(maxAttempts = 3, backoff = @Backoff(delay = 2000))
public void sendAsync(EmailRequest request) {
    try {
        sender.sendHtmlEmail(request.getTo(), request.getSubject(), request.getContent());
        log.info("郵件發送成功: {}", request.getTo());
    } catch (MessagingException e) {
        log.error("郵件發送失敗: {}", request.getTo(), e);
        throw new EmailSendException(e); // 觸發重試
    }
}

配合線程池 `@EnableAsync`、重試機制 `@EnableRetry`、熔斷器,構建高可用郵件服務。

總結

JavaMail 發送郵件核心在於:正確的 SSL/TLS 配置 + 授權碼認證 + 敏感信息外部化。本文提供從基礎發送到生產級異步重試的完整方案,涵蓋 HTML、附件、內嵌圖片、群發等常見需求。記住:授權碼即密碼,嚴禁提交代碼倉庫,請使用配置中心或密鑰管理系統托管。

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