【我的Segmentfault原文】https://segmentfault.com/a/1190000008030346

前言

  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邮箱发送邮件,尝试C@126.com发送给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.

三、附录

1、SMTP错误码及建议解决方法
2、SMTP errors and reply codes
3、javaMail发送邮件成功却收不到邮件或收到邮件无主题无收件人乱码
4、新浪邮箱诚信平台

JavaMail邮件发送不成功的那些坑人情况及分析说明的更多相关文章

  1. javamail邮件发送例子

    public class EmailTask{        // Session used by the javamail classes    private Session session;   ...

  2. Spring的javaMail邮件发送(带附件)

    项目中经常用到邮件功能,在这里简单的做一下笔记,方便日后温习. 首先需要在配置文件jdbc.properties添加: #------------ Mail ------------ mail.smt ...

  3. javaMail 邮件发送和接收示例,支持正文图片、html、附件(转)

    转自:https://blog.csdn.net/star_fly4/article/details/52037587 一.RFC882文档简单说明 RFC882文档规定了如何编写一封简单的邮件(纯文 ...

  4. JavaMail 邮件发送

    jar包部署 /** * 通过SMTP进行邮件集成 */ public class CmpSendMail { // 邮件发送服务器主机 private final static String HOS ...

  5. jenkins构建邮件自动发送,测试邮件发送成功,构建项目邮件发送不成功的问题

    提示问题: Connection error sending email,retrying once more in 10 seconds…… Connection error sending ema ...

  6. 应用层之E-mail服务及javaMail邮件发送的知识总结

    关于Email服务你需要知道的知识点: 概述: 今天来介绍一下应用层的电子邮件服务,我们每天几乎都在用,电子邮件(email)服务也是一种基于C/S模式的服务,它采用的是一种"存储-转发&q ...

  7. javaMail邮件发送的简单实现

    package com.test.mail; import java.util.Properties; import javax.mail.Message; import javax.mail.Ses ...

  8. javaMail邮件发送功能(多收件人,多抄送人,多密送人,多附件)

    private Session session; private Transport transport; private String mailHost = ""; privat ...

  9. (转)JavaMail邮件发送-发送一个文本邮件和一些问题说明

    需要下载的JAR包: JavaMail:http://www.oracle.com/technetwork/java/javamail/index.html JAF:http://www.oracle ...

随机推荐

  1. Linux笔记(十) - 权限管理

    (1)ACL权限1.查看分区ACL权限是否开启:dumpe2fs -h /dev/sda3-h 仅显示超级块中信息,而不显示磁盘块组的详细信息2.临时开启分区ACL权限:mount -o remoun ...

  2. Dockerfile的书写规则及指令使用方法

    Dockfile是一种被Docker程序解释的脚本,Dockerfile由一条一条的指令组成,每条指令对应Linux下面的一条命令.Docker程序将读取Dockerfile,根据指令生成定制的ima ...

  3. Kettle(Pentaho)实现web方式远程执行job或transformation

    一.背景 公司在用kettle做数据etl,每做完一个job或transformation发布上线想要立即执行看数据效果的话每次都是找运维同学登陆服务器打开kettle找到对应的文件点击执行,整个过程 ...

  4. Ubuntu 16.04安装配置Samba服务

    Samba是开源软件,用来让Linux系统与Windows系统的SMB/CIFS网络协定做连结,实现Windows主机与Linux服务器之间的资源共享.Samba服务为两种不同的操作系统架起了一座桥梁 ...

  5. 【iOS 录音转码MP3及转码BASE64上传】

    iOS 录音转码MP3及转码BASE64上传 一,开始录音 NSLog(@"开始录音"); [self startRecord]; - (void)startRecord { // ...

  6. for语句输出图形

    一.输出以下图形 ******************************** 用for...for...嵌套循环,内循环控制每一行的个数(即列数),外循环控制行数 class ForDraw { ...

  7. UUID错误

    在Archive项目时,出现了“Your build settings specify a provisioning profile with the UUID “”, however, no suc ...

  8. 根据dba_hist_osstat统计CPU占用情况

    在11g里面,视图dba_hist_osstat用来记录OS级别的time时间指标.视图dba_hist_osstat_name显示了相关的指标名称. SYS@/dzgddb> select * ...

  9. jQuery 监听元素内容变化的方法

    我们可以用onchange事件来完成元素值发生改变触发的监听.但是 onchange 比较适用于<input>.<textarea> 以及 <select> 元素. ...

  10. java对获取的字节数组进行处理

    java对获取的字节数组bytes[]进行处理: 第一种,直接将该字节数组转换为字符串(部分): String content = ,); //从位置0开始获取2个字节 这样,对获取的数据报进行全部转 ...