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

JavaMail 郵件發送全攻略:SMTP/POP3/IMAP 協議詳解、文本/HTML/附件/內嵌圖片實戰代碼

     編輯:Java 綜合教學

郵件協議速覽

協議全稱端口作用模式
SMTPSimple Mail Transfer Protocol25/465/587**發送**郵件(MTA 間轉發)推/存儲-轉發
POP3Post Office Protocol v3110/995**接收**郵件(下載到本地,可選刪除服務器副本)拉/離線優先
IMAPInternet Message Access Protocol143/993**接收**郵件(服務器管理,多端同步、郵箱操作、搜索、旗標)拉/在線優先

MIME (Multipurpose Internet Mail Extensions):將二進制(圖片、附件)編碼為文本(Base64/Quoted-Printable)以便 SMTP 傳輸。

JavaMail 核心 API 對照

依賴坐標(Jakarta Mail 2.0+ / JavaMail 1.6)

<!-- Jakarta Mail (Spring Boot 3 / Jakarta EE 9+) -->
<dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>jakarta.mail</artifactId>
    <version>2.0.1</version>
</dependency>

<!-- 兼容舊版 -->
<dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>javax.mail</artifactId>
    <version>1.6.2</version>
</dependency>

實戰一:純文本郵件(兩種認證方式)

方式 A:Session.getInstance(props) + Transport 手動連接

Properties props = new Properties();
props.put("mail.smtp.host", "smtp.163.com");
props.put("mail.smtp.port", "465");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.ssl.enable", "true");  // SSL 隱式
props.put("mail.transport.protocol", "smtp");

Session session = Session.getInstance(props);
session.setDebug(true); // 開啟調試輸出

MimeMessage msg = new MimeMessage(session);
msg.setFrom(new InternetAddress("sender@163.com", "發件人", "UTF-8"));
msg.setRecipient(Message.RecipientType.TO, new InternetAddress("receiver@qq.com"));
msg.setSubject("測試郵件", "UTF-8");
msg.setText("你好,這是純文本郵件。", "UTF-8");

try (Transport transport = session.getTransport("smtp")) {
    transport.connect("smtp.163.com", "sender@163.com", "授權碼"); // 注意:授權碼非登錄密碼
    transport.sendMessage(msg, msg.getAllRecipients());
}

方式 B:Session.getInstance(props, Authenticator) + Transport.send 靜態發送

Session session = Session.getInstance(props, new Authenticator() {
    @Override protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication("sender@163.com", "授權碼");
    }
});

MimeMessage msg = new MimeMessage(session);
// ... 設置內容同方式 A
Transport.send(msg); // 內部自動連接、發送、關閉

實戰二:HTML 富文本郵件

msg.setContent("<h1 style='color:#2c3e50'>HTML 郵件</h1><p>支援 <b>粗體</b>、<a href='https://example.com'>鏈接</a></p>", "text/html;charset=UTF-8");

實戰三:帶附件郵件(Multipart 混合模式)

MimeMultipart multipart = new MimeMultipart("mixed"); // mixed: 附件模式

// 部件 1:正文
MimeBodyPart textPart = new MimeBodyPart();
textPart.setContent("請查收附件。", "text/plain;charset=UTF-8");
multipart.addBodyPart(textPart);

// 部件 2:附件
MimeBodyPart filePart = new MimeBodyPart();
filePart.attachFile(new File("D:/report.pdf")); // 自動設置 Content-Disposition: attachment
// 解決中文文件名亂碼
filePart.setFileName(MimeUtility.encodeText("季度報告.pdf", "UTF-8", "B"));
multipart.addBodyPart(filePart);

msg.setContent(multipart);

實戰四:內嵌圖片郵件(Related 模式 + CID 引用)

MimeMultipart root = new MimeMultipart("related"); // related: 內嵌資源模式

// 部件 1:HTML 正文,圖片用 cid:imageId 引用
MimeBodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent("<h1>內嵌圖片</h1><img src='cid:logo' />", "text/html;charset=UTF-8");
root.addBodyPart(htmlPart);

// 部件 2:圖片資源,設置 Content-ID 對應 cid
MimeBodyPart imagePart = new MimeBodyPart();
imagePart.attachFile(new File("D:/logo.png"));
imagePart.setContentID("<logo>"); // 必須包含尖括號
imagePart.setDisposition(MimeBodyPart.INLINE);
root.addBodyPart(imagePart);

msg.setContent(root);

實戰五:混合場景(HTML 正文 + 內嵌圖片 + 附件)

MimeMultipart mixed = new MimeMultipart("mixed");

// 子層 related:HTML + 內嵌圖片
MimeMultipart related = new MimeMultipart("related");
MimeBodyPart html = new MimeBodyPart();
html.setContent("...<img src='cid:chart' />...", "text/html;charset=UTF-8");
related.addBodyPart(html);
MimeBodyPart chart = new MimeBodyPart();
chart.attachFile(new File("chart.png"));
chart.setContentID("<chart>");
chart.setDisposition(MimeBodyPart.INLINE);
related.addBodyPart(chart);

// 將 related 包裝為 mixed 的一個部件
MimeBodyPart relatedWrapper = new MimeBodyPart();
relatedWrapper.setContent(related);
mixed.addBodyPart(relatedWrapper);

// 附件部件直接加入 mixed
MimeBodyPart attachment = new MimeBodyPart();
attachment.attachFile(new File("data.xlsx"));
attachment.setFileName(MimeUtility.encodeText("數據.xlsx", "UTF-8", "B"));
mixed.addBodyPart(attachment);

msg.setContent(mixed);

常見問題與解決

類/介面包角色關鍵方法
Sessionjavax.mail郵件會話上下文,連接屬性、認證器getInstance(props, authenticator)
Message / MimeMessagejavax.mail / .inernet郵件對象(主題、發件人、收件人、內容)setFrom/setRecipients/setSubject/setContent
Address / InternetAddressjavax.mail / .internet郵箱地址封裝new InternetAddress("a@b.com", "Name")
Transportjavax.mail發送傳輸(SMTP 實現)send(msg) / connect/sendMessage/close
Store / Folderjavax.mail接收存儲(POP3/IMAP 實現)store.getFolder("INBOX")
MimeMultipart / MimeBodyPartjavax.mail.internet多部件郵件容器/部件(文本+附件+內嵌)addBodyPart / setContent
問題原因解決
535 Error: authentication failed用戶名/授權碼錯誤、未開啟 SMTP 服務郵箱設置開啟 SMTP、生成專用授權碼
Could not connect to SMTP host端口/SSL 模式不匹配、防火牆攔截465=SSL、587=STARTTLS、25=平文(多被封)
中文附件名亂碼RFC 2231 編碼缺失`MimeUtility.encodeText(filename, "UTF-8", "B")`
內嵌圖片不顯示Content-ID 格式錯誤、cid 引用不匹配`setContentID("")` + HTML `src='cid:id'`
大附件發送失敗郵箱限制(通常 20-50MB)、超時分卷壓縮、雲存儲鏈接、調大 timeout

生產級最佳實踐

  1. 異步發送:`@Async` + 線程池,或消息隊列(RabbitMQ/Kafka)削峰填谷。
  2. 模板引擎:Thymeleaf/FreeMarker 渲染 HTML,分離業務與視圖。
  3. 配置外部化:Spring Boot `spring.mail.*` 自動配置 `JavaMailSender`,注入即用。
  4. 重試與熔斷:Resilience4j 重試 3 次、指數退避,熔斷保護下游。
  5. 日誌審計:記錄 Message-ID、收件人、發送耗時、狀態,便於追蹤。

Spring Boot 整合一鍵啟用

spring:
  mail:
    host: smtp.163.com
    port: 465
    username: sender@163.com
    password: auth_code
    protocol: smtp
    properties:
      mail:
        smtp:
          ssl:
            enable: true
          auth: true
          starttls:
            enable: false
        debug: false

// 使用
@Autowired JavaMailSender mailSender;

public void sendSimple(String to, String subject, String text) {
    SimpleMailMessage msg = new SimpleMailMessage();
    msg.setTo(to); msg.setSubject(subject); msg.setText(text);
    mailSender.send(msg);
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved