Java JavaMail通過SMPT發送郵件
概述
本講講述如何使用JavaMail工具包,通過SMPT協議,在Java程式碼中發送郵件。
一、JavaMail簡介
JavaMail API提供了一個獨立於平台且與協議無關的框架來構建郵件和消息傳遞應用程式。 JavaMail API提供了一組抽象類,用於定義組成郵件系統的對象。 它是一個可選包(標準擴展名),用於閱讀,撰寫和發送電子郵件。我們可以基於JavaMail開發出類似於Microsoft Outlook的應用程式。
JavaMail提供了用於構建消息傳遞系統介面的元素,包括系統組件和介面。 雖然此規範沒有定義任何特定的實現,但JavaMail確實包含幾個實現RFC822和MIME Internet消息傳遞標準的類。 這些類作為JavaMail類包的一部分提供。
以下是JavaMail API支援的一些協議:
- SMTP : Simple Mail Transfer Protocol縮寫。 它提供了一種傳遞電子郵件的機制。
- POP : Post Office Protocol縮寫。 POP是大多數人用來獲取郵件的機制。 它定義了對每個用戶的單個郵箱的支援。 RFC 1939定義了該協議。
- IMAP : Internet Message Access Protocol縮寫。 它是用於接收消息的高級協議。 它為每個用戶提供多個郵箱支援,此外,郵箱可以由多個用戶共享。 它在RFC 2060中定義。
- MIME : Multipurpose Internet Mail Extensions縮寫。 。 它不是郵件傳輸協議。 相反,它定義了傳輸內容:消息的格式,附件等。 這裡有許多不同的文檔:RFC 822,RFC 2045,RFC 2046和RFC 2047.作為JavaMail API的用戶,您通常不需要擔心這些格式。 但是,這些格式確實存在並由您的程式使用。
- NNTP and Others :第三方提供商提供了許多協議。 其中一些是網路新聞傳輸協議(NNTP),安全多用途Internet郵件擴展(S/MIME)等。
JavaMail包中用於處理電子郵件的核心類是:Session,Message,Address,Authenticator,Store,Transport, Folder等。Session定義了一個基本的郵件會話,它需要從Properties中讀取類似於郵件伺服器,用戶名和密碼等資訊。不過JDK中並沒有包含,使用JavaMail發送郵件需要使用Sun發布的mail.jar和activtion.jar兩個包。

開啟郵箱客戶端的SMTP協議功能
通過郵箱服務供應商,使用SMTP協議發送郵件一般需要開啟許可權並獲取SMTP用戶認證資訊。
以163郵箱為例,需要在163郵箱網頁上設置,並申請開啟功能。然後你將獲取一個密鑰(記錄保存下來),你的郵箱帳號加上這個密鑰就是接下來用於SMTP用戶認證的用戶名和密碼。
可以參考開啟客戶端協議的官方文檔 。
程式碼
String username = "[email protected](這是一個郵箱)";// TODO: 按需修改
String password = "這是一個密碼(一般在郵箱服務商上申請)";// TODO: 按需修改
/******************************************** 第一步,設置郵箱伺服器相關的鏈接和屬性 **/
//協議的配置屬性
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.163.com");//郵箱服務區地址// TODO: 按需修改
//使用非ssl埠
props.put("mail.smtp.port", "25");
//使用ssl埠
// final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
// props.put("mail.smtp.socketFactory.port", "465");
// props.put("mail.smtp.socketFactory.class", SSL_FACTORY);
// props.put("mail.smtp.socketFactory.fallback", "false");
// props.put("mail.smtp.starttls.enable", "true");
//上面的 ssl埠 和 非ssl埠 二選一
//開啟smtp用戶認證
props.put("mail.smtp.auth", "true");
//獲取郵件session(此session不同於http session),傳遞Authenticator對象,用於用戶身份認證
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
//開啟session運行時的debug日誌輸出
session.setDebug(true);
/******************************************** 第二步,開始設置郵件的屬性 **/
//Message對象,將存儲我們實際發送的電子郵件資訊
MimeMessage message = new MimeMessage(session);
//設置發件方地址
message.setFrom(new InternetAddress("一個郵件地址"));// TODO: 按需修改
/**
* 設置接受方地址(收件方地址的情況)
* Message.RecipientType.TO 表示主要的接收方
* Message.RecipientType.CC 表示抄送
* Message.RecipientType.BCC 表示密送
* 發送給單個或多個接收方可以自由組合,或者取其一種
*/
message.setRecipient(Message.RecipientType.TO, new InternetAddress("郵件地址1"));// TODO: 按需修改
//同時發給多個接收方的時候用這個
InternetAddress[] internetAddresses = new InternetAddress[2];
internetAddresses[0] = new InternetAddress("郵件地址1");// TODO: 按需修改
internetAddresses[1] = new InternetAddress("郵件地址2");// TODO: 按需修改
message.setRecipients(Message.RecipientType.CC, internetAddresses);
//設置郵件主題(標題)
message.setSubject("Hello Subject", "UTF-8");
/******************************************** 第三步,開始填充郵件的內容(郵件正文) **/
//////////第一種形式,純文本正文(可以設置為html格式的字元串,郵件客戶端會自動解析成html)
// String textBody = "hello, this email was sent via JavaMail.";
// message.setText(textBody, "UTF-8");
//////////第二種形式,MIME形式的正文(可以給郵件添加附件,或者給html添加關聯的附件等)
Multipart multipart = new MimeMultipart();
BodyPart htmlTextpart = new MimeBodyPart();
//html中內嵌圖片,通過網頁urlimg方式(這種方式圖片數據在互聯網上)
String htmlImageUrl = "//pic.cnblogs.com/avatar/2062798/20200614130312.png";// TODO: 按需修改
String body = "<h1>Hello</h1><p><img src=\"" + htmlImageUrl + "\" alt=\"圖片載入失敗,請嘗試刷新頁面\" referrerpolicy=\"no-referrer\"></p>";
//html中內嵌圖片,通過附件附件方式(這種方式圖片數據在郵件中)
body += "<h1>Hello2</h1><p><img src=\"cid:img01\" alt=\"圖片載入失敗,請嘗試刷新頁面\" referrerpolicy=\"no-referrer\"></p>";
htmlTextpart.setContent(body, "text/html;charset=utf-8");
multipart.addBodyPart(htmlTextpart);
//打開要嵌入的文件
File file = new File("C:\\Users\\user\\Pictures\\Camera Roll\\image.jpg");// TODO: 按需修改
InputStream inputStream = new FileInputStream(file);
BodyPart imagepart = new MimeBodyPart();
imagepart.setFileName("一張平平無奇的圖片.jpg");//
imagepart.setDataHandler(new DataHandler(new ByteArrayDataSource(inputStream, "image/jpeg")));
imagepart.setHeader("Content-ID", "<img02>");//value要和圖片的cid對應才能嵌入在html中,否則就會變成附件
multipart.addBodyPart(imagepart);
//郵件的附件(圖片不設置header就是附件)
BodyPart attachment = new MimeBodyPart();
attachment.setFileName("一張平平無奇的圖片.jpg");//
attachment.setDataHandler(new DataHandler(new ByteArrayDataSource(inputStream, "image/jpeg")));
multipart.addBodyPart(attachment);
//要調用setContent填入正文資訊,和純文本的形式不同
message.setContent(multipart);
//通過Transport類發送郵件(這時候才開始有網路連接)
Transport.send(message);
maven依賴
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
什麼是SMTP
SMTP(Simple Mail Transfer Protocol)即簡單郵件傳輸協議,它是一組用於由源地址到目的地址傳送郵件
的規則,由它來控制信件的中轉方式。SMTP協議屬於TCP/IP協議簇,它幫助每台電腦在發送或中轉信件
時找到下一個目的地。通過SMTP協議所指定的伺服器,就可以把E-mail寄到收信人的伺服器上了,整個過程
只要幾分鐘。SMTP伺服器則是遵循SMTP協議的發送郵件伺服器,用來發送或中轉發出的電子郵件。SMTP
是一種TCP協議支援的提供可靠且有效電子郵件傳輸的應用層協議。
什麼是MIME
MIME, 全稱為「Multipurpose Internet Mail Extensions」, 比較確切的中文名稱為「多用途互聯網郵件擴展」。它是當前廣泛應用的一種電子郵件技術規範,基本內容定義於RFC 2045-2049
什麼是MIME類型?-在把輸出結果傳送到瀏覽器上的時候,瀏覽器必須啟動適當的應用程式來處理這個輸出文檔。這可以通過多種類型MIME(多功能網際郵件擴充協議)來完成。在HTTP中,MIME類型被定義在Content-Type header中。
MIME不屬於一個郵件傳輸協議,它只是對SMTP的一個擴展,不能替代SMTP協議,至於為啥要替換SMTP了。主要是因為SMTP協議在傳輸報文時,只能夠傳輸7位的ASCII格式的報文,不支援那些不使用7位ASCII格式的語種,同時它也不支援語音和影片數據的傳輸,因此我們需要一個輔助性協議幫忙傳輸報文,它就是MIME。
參考
JavaMail - 教程
廖雪峰教程 - 發送email
SMTP增強狀態程式碼註冊表
JavaMail--基礎類詳解
使用JavaMail發送郵件,465埠開啟ssl加密傳輸
JavaMail配置屬性
SMTP協議介紹
如果有不對的地方感謝指出

