天天看點

【Java】Mail郵件發送不成功的案例分析

前言

  JavaMail的使用本身并不難,網上有不少案例,簡單易懂,而且有詳細的中文注解。但是由于JavaMail的機制設定不夠完善,特别是異常出錯時的參考資訊太少,給初學者造成了不少麻煩,而我就是其中之一。在此,把我遇到過得那些坑總結出來,以免大家重蹈覆轍,浪費時間。(注:後續還有遇到新的問題,我會持續更新到這裡)

一、JavaMail概述

  JavaMail是由Sun定義的一套收發電子郵件的API,不同的廠商可以提供自己的實作類。但它并沒有包含在JDK中,而是作為JavaEE的一部分。

  廠商所提供的JavaMail服務程式可以有選擇地實作某些郵件協定,常見的郵件協定包括:

  • SMTP:簡單郵件傳輸協定,用于發送電子郵件的傳輸協定;
  • POP3:用于接收電子郵件的标準協定;
  • IMAP:網際網路消息協定,是POP3的替代協定。

  這三種協定都有對應SSL加密傳輸的協定,分别是SMTPS,POP3S和IMAPS。除JavaMail服務提供程式之外,JavaMail還需要JAF(JavaBeans Activation Framework)來處理不是純文字的郵件内容,這包括MIME(多用途網際網路郵件擴充)、URL頁面和檔案附件等内容。下圖描述了JavaMail的體系結構。

(圖檔來源:http://blog.csdn.net/t12x3456...)

  • mail.jar:此JAR檔案包含JavaMail API和Sun提供的SMTP、IMAP和POP3服務提供程式;
  • activation.jar:此JAR檔案包含JAF API和Sun的實作。

(有關JavaMail的介紹我隻摘要部分,詳細介紹請參考:http://blog.csdn.net/zapldy/a...)

二、各種問題及分析說明

  後面列舉出來的報錯資訊需要開啟Session的debug模式,具體配置方式如下:

Session sendMailSession = Session.getInstance(pro, authenticator);
sendMailSession.setDebug(true);
           

1、背景顯示郵件發送成功但未收到郵件

問題現象

  使用新浪郵箱發送郵件,嘗試兩種郵件發送方式,分别是“A@sina .cn發送給A@sina .cn”和“A@sina .cn發送給B@sina .cn”,摘要部分背景列印資訊:

250 ok queue id 355937395546
QUIT
221 smtp-5-121.smtpsmail.fmail.xd.sinanode.com Sent message ***@sina.cn successfully....            

  使用163郵箱發送郵件,嘗試[email protected]發送給A@sina .cn,摘要部分背景列印資訊:

250 Mail OK queued as smtp7,C8CowADnDNooqmNYHWsYGw--.30359S3 1482926655 QUIT 221 Bye Sent message ***@sina.cn successfully....                 

  登入新浪郵箱确認有smtp服務且處于開通狀态,也嘗試重新開啟smtp服務,仍然郵件發送不成功。網上也有不少人回報用手機用戶端無法使用新浪郵箱發送郵件,随後我嘗試用foxmail登入新浪郵箱,也出現隻能接收郵件而不能發送郵件的情況。

問題分析

  基本确定是新浪郵箱問題,至于是smtp服務問題,還是做什麼限制就不清楚了。好像平時也沒多少人用新浪郵箱發郵件,通過網頁登入也是能發郵件的,湊合能用,畢竟是免費郵箱嘛。

  這是用JavaMail發送郵件遭遇的第一個問題,案例都是參考别人原封不動拿過來用的,卻發了收不到郵件。

換了幾個參考案例,問題現象相同。我開始懷疑别人給的案例代碼問題,畢竟堂堂的新浪郵箱還不至于這麼不靠譜。然後,就是基于這樣的判斷,我就吃了大虧

,一直在分析代碼和配置方式,也在各大論壇搜“發送郵件成功卻收不到郵件”,發現出現問題的不在少數,而且多半給出的建議是檢查代碼有沒有問題,然後提問的人也沒了回複下文,這就導緻了很大的誤導性。這正是因為這個原因,我也白白地耗了好幾天時間,直到最後發現原來原因是這麼簡單...

有時别人的解答能夠事半功倍,但是這種依賴性還是不靠譜的,有時自己的排錯思路更重要

2、向新浪郵箱發信被退信

問題現象

  平時開發測試,不想用私人常用郵箱,于是注冊了搜狐郵箱,并嘗試向新浪郵箱發送郵件,不過很快搜狐郵箱收到退信(這種情況JavaMail是不會提示判斷資訊的),退信内容如下:

<A@sina .cn>: host freemx1.sinamail.sina.com.cn[202.108.35.47] said:

554 Rejected due to the sending MTA's poor reputation. Please refer

http://mail.sina.com.cn/help2... Please refer to

http://chengxin.mail.sina.com... 123.125.123.1

(in reply to DATA command)

問題分析

  通過通路退信資訊裡面的連結(新浪郵箱誠信平台),基本确定搜狐郵箱伺服器被拉黑了。當然,不是被新浪拉黑,而是進了RBL黑名單,新浪參考其資料進行了屏蔽。這個已經超出了個人能力範圍,果斷放棄新浪郵箱,改向其他郵箱發送。

【RBL黑名單】

RBL是英文Realtime BlackholeList的縮寫,即實時黑名單清單。在該清單中的IP位址對外釋出過垃圾郵件。是由第三方的反垃圾郵件組織提供的檢查垃圾郵件發送者位址的服務。

【查詢網站】

MXToolBox:http://mxtoolbox.com/ 

BlackListAlert:http://www.blacklistalert.org/

3、向163郵箱發信未收到且也無未退信

問題現象

  通過搜狐郵箱向新浪郵箱發信遭遇退信後,我嘗試自己發給自己,正常收到郵件。考慮模拟測試要盡量真實,我改向163郵箱發信,結果出現背景顯示發信成功,163郵箱卻沒收到郵件,但本地郵箱并沒收到退信通知。

問題分析

  這說明“

背景顯示郵件發送成功但未收到郵件

”的情況,原因還是多種多樣的,不僅可能發件伺服器有問題,還可能是收件伺服器的問題。收件伺服器有的給你退信,有的還收了直接丢棄,真是什麼奇葩情況都有,多加注意吧。

4、jar包重疊存在javax.mail.*

問題現象

  從Oracle官網下載下傳下來JavaMail相關jar包是mail.jar,導入進去測試後報各種奇葩錯誤。下面的異常資訊是在項目中已有geronimo-javamail_1.4_spec-1.3.jar的情況下導入mail.jar後報出來的:

com.sun.mail.smtp.SMTPSendFailedException: 530 Authentication required at com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:1388) at com.sun.mail.smtp.SMTPTransport.mailFrom(SMTPTransport.java:959) at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:583)                 

  不仔細看還以為是賬号或密碼填錯了,其實隻要把geronimo-javamail_1.4_spec-1.3.jar剔除,重新發郵件就正常了。

問題分析

  上面隻是我貼出來的報錯情況之一,這些報錯是不一定能夠複現,因為導包就存在問題,重疊存在javax.mail.*。我是在出現第一個問題(“

背景顯示郵件發送成功但未收到郵件

”)的時候,在網上看到别人說的這種情況(javaMail發送郵件成功卻收不到郵件或收到郵件無主題無收件人亂碼),而後我就開始逐個排查定位,目前通過我所知道的情況來看,重疊存在javax.mail.*的jar有mail.jar、geronimo-javamail_1.4_spec-1.x.jar、mailapi.jar和javaee.jar。

  排查的方法也很簡單,比如打開javax.mail.Session,然後定位它所在的jar,剔除後再找下一個jar包。

5、jar包正确的情況下也出現報錯

問題現象

  在jar包正常且配置正确的情況下,我也遇到過不少報錯情況。出現的情況基本是前幾次發郵件都正常,然後再發一次又突然出現報錯,再試一次問題又不複現,貼出幾種報錯資訊如下:

(報錯1)

DEBUG SMTP: Sending failed because of invalid destination addresses
RSET
DEBUG SMTP: MessagingException while sending, THROW: 
javax.mail.SendFailedException: Invalid Addresses;
  nested exception is:
    com.sun.mail.smtp.SMTPAddressFailedException: 554 5.7.1 <*@163.com>: Relay access denied at com.sun.mail.smtp.SMTPTransport.rcptTo(SMTPTransport.java:1862) at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1118)                

(報錯2)

Exception in thread "main" java.lang.RuntimeException: javax.mail.MessagingException: Could not convert socket to TLS;
  nested exception is: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: timestamp check failed                

(報錯3)

javax.mail.SendFailedException: Send failure (javax.mail.MessagingException: Could not connect to SMTP host: smtp.sohu.com, port: 25 (java.net.ConnectException: Connection timed out: connect))
    at javax.mail.Transport.send(Transport.java:163) at javax.mail.Transport.send(Transport.java:48) at javamail.EmailSender.sendMail(EmailSender.java:91) at javamail.EmailSender.main(EmailSender.java:64)           

(報錯4)

250-zw_71_47
250-AUTH PLAIN LOGIN
250 STARTTLS
DEBUG SMTP: Found extension "AUTH", arg "PLAIN LOGIN" DEBUG SMTP: Found extension "STARTTLS", arg "" DEBUG SMTP: Attempt to authenticate using mechanisms: LOGIN PLAIN DIGEST-MD5 NTLM DEBUG SMTP: AUTH LOGIN command trace suppressed            

問題分析

  因為這些報錯不具有可複現性,測試過程中我也司空見慣,當然90%以上的情況郵件發送都是正常,代碼方面也是綜合了多個案例提煉出來的,而且代碼大同小異,也看過官方提供的樣例,配置内容都差不多,代碼問題可能性較小,也不排除smtp伺服器抽風了,目前我暫時忽略。   當然,如果有分析出是代碼問題,也歡迎留言告知分享。(注:後面文章我會将我的代碼粘貼出來共享)

6、發信成功後,回應的資訊不同

問題現象

  我将JavaMail代碼在外網測試郵件發送成功時,背景列印資訊結尾内容基本如下:

250 Mail OK queued as smtp7,C8CowADnDNooqmNYHWsYGw--.30359S3 1482926655
QUIT
221 Bye           

  當我将JavaMail代碼移植到内部環境測試郵件發送成功時,背景列印資訊結尾内容如下:

250 Message accepted for delivery
QUIT
221 srv201.mail.*.* SMTP Service closing transmission channel
           

問題分析

  通過上網查詢資料得知,250和221這樣的編碼實際是smtp互動的消息編碼,其中221代表郵件會話即将結束,這意味着所有消息都已被處理。編碼後面的資訊“srv201.mail.. SMTP Service closing transmission channel”和“Bye”的意思類似,可以忽略具體内容,知道221代表郵件發送正常即可。

221 The server is closing its transmission channel. It can come with side messages like "Goodbye" or "Closing connection". The mailing session is going to end, which simply means that all messages have been processed.