JavaMail 保證郵件傳送成功的方法總結

hollischuang發表於2015-12-08

使用過JavaMail的api傳送郵件的人可能會有這樣一個疑惑:我如何知道我呼叫該api傳送的郵件是否成功呢?一般的開放的api給我們呼叫都會有個返回值或者狀態碼,來告訴我們執行成功與否。但是JavaMail卻沒有提供這樣一個返回值。

所以在呼叫JavaMail傳送郵件的時候,我們只能通過catch異常的方式來判斷郵件是否傳送成功。我們認為只要沒有異常發生,那麼郵件就能傳送成功。那麼我們就來分析一下JavaMail為什麼沒有提供返回值,和通過異常判斷郵件傳送成功狀態是否靠譜。

JavaMail傳送郵件原理

在使用JavaMail進行傳送郵件時,我們必須提供一個郵件會話。建立郵件會話的過程如下:

Properties props = new Properties();
        // 傳送郵件的伺服器的IP和埠 
        props.put("mail.smtp.host", MAIL_SMTP_HOST);
        props.put("mail.smtp.port", MAIL_SMTP_PORT);
        // 是否需要身份驗證
        props.put("mail.smtp.auth", "true");

        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        Session session = Session.getDefaultInstance(props, new Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
            // 登陸郵件傳送伺服器的使用者名稱和密碼 
                return new PasswordAuthentication(MAIL_SENDER_MAIL, MAIL_SENDER_PASS);
            }
        });

分析一下程式碼。在建立Session之前我們先建立一個Properties,這個Properties設定了這樣幾個引數:mail.smtp.host、mail.smtp.port、mail.smtp.auth和mail.smtp.socketFactory.class。在建立Session的時候還要傳入傳送郵件使用的使用者名稱及密碼。

傳送郵件程式碼如下:

//使用JavaMail傳送郵件的5個步驟
        //1、建立session
         Session session = Session.getInstance(prop);
         //開啟Session的debug模式,這樣就可以檢視到程式傳送Email的執行狀態
         session.setDebug(true);
         //2、通過session得到transport物件
         Transport ts = session.getTransport();
         //3、使用郵箱的使用者名稱和密碼連上郵件伺服器,傳送郵件時,發件人需要提交郵箱的使用者名稱和密碼給smtp伺服器,使用者名稱和密碼都通過驗證之後才能夠正常傳送郵件給收件人。
         ts.connect("smtp.sohu.com", "gacl", "郵箱密碼");
         //4、建立郵件
         Message message = createSimpleMail(session);
         //5、傳送郵件
         ts.sendMessage(message, message.getAllRecipients());
         //關閉連線
         ts.close();

總結髮送郵件過程主要有以下幾個步驟:

1.建立包含郵件伺服器的網路連結的Session物件
2.建立代表郵件內容的Message物件
3.建立Transport物件
4.連結伺服器
5.傳送Message
6.關閉連結

由於Transport只是一個抽象類,所以這裡在傳送Message的時候用呼叫的方法ts.sendMessage實際上是呼叫的Transport的實現類SMTPTransport的sendMessage方法。

而SMTPTransport的sendMessage方法則依賴SMTP協議進行郵件的傳送。

所以,當javamail使用smtp服務傳送郵件時,當你把郵件傳送到smtp伺服器的時候,你只能得到已經傳送到smtp的佇列中的狀態,但是郵件伺服器是否能傳送成功,你是得不到的。就是說,你不能保證郵件傳送一定成功。 這就取決於SMTP協議的內容傳輸了。

但是SMTP協議如果傳輸失敗,是會報錯的。SMTP由TCP提供的可靠的資料傳輸服務把郵件訊息從發信人的郵件伺服器傳送到收信人的郵件伺服器。

所以我們可以認為當我們呼叫JavaMail傳送郵件時,如果程式沒有報錯則表示郵件傳送成功。

SMTP工作機制

SMTP通常有兩種工作模式:傳送SMTP和接收SMTP。

具體工作方式為:傳送SMTP在接到使用者的郵件請求後,判斷此郵件是否為本地郵件,若是直接投送到使用者的郵箱,否則向dns查詢遠端郵件伺服器的MX紀錄,並建立與遠端接收SMTP之間的一個雙向傳送通道,此後SMTP命令由傳送SMTP發出,由接收SMTP接收,而應答則反方面傳送。一旦傳送通道建立,SMTP傳送者傳送MAIL命令指明郵件傳送者。如果SMTP接收者可以接收郵件則返回OK應答。SMTP傳送者再發出RCPT命令確認郵件是否接收到。如果SMTP接收者接收,則返回OK應答;如果不能接收到,則發出拒絕接收應答(但不中止整個郵件操作),雙方將如此重複多次。當接收者收到全部郵件後會接收到特別的序列,如果接收者成功處理了郵件,則返回OK應答即可。

SMTP工作過程

簡單郵件傳輸協議(SMTP)是一種基於文字的電子郵件傳輸協議,是在因特網中用於在郵件伺服器之間交換郵件的協議。SMTP是應用層的服務,可以適應於各種網路系統。

SMTP的命令和響應都是基於文字,以命令列為單位,換行符為CR/LF。響應資訊一般只有一行,由一個3位數的程式碼開始,後面可附上很簡短的文字說明。

SMTP要經過建立連線、傳送郵件和釋放連線3個階段。具體為:

(1)建立TCP連線。
(2)客戶端向伺服器傳送HELO命令以標識發件人自己的身份,然後客戶端傳送MAIL命令。
(3)伺服器端以OK作為響應,表示準備接收。
(4)客戶端傳送RCPT命令。
(5)伺服器端表示是否願意為收件人接收郵件。
(6)協商結束,傳送郵件,用命令DATA傳送輸入內容。
(7)結束此次傳送,用QUIT命令退出。

SMTP伺服器基於DNS中的郵件交換(MX)記錄路由電子郵件。電子郵件系統發郵件時是根據收信人的地址字尾來定位郵件伺服器的。SMTP通過使用者代理程式(UA)完成郵件的編輯、收取和閱讀等功能;通過郵件傳輸代理程式(MTA)將郵件傳送到目的地。

相關文章