一、邮件服务器与传输协议

要在网络上实现邮件功能,必须要有专门的邮件服务器。这些邮件服务器类似于现实生活中的邮局,它主要负责接收用户投递过来的邮件,并把邮件投递到邮件接收者的电子邮箱中。

SMTP有关的详细内容可以看看   《TCP/IP详解  卷一》   第28章会比较清晰,这里有一个地址,可以看看   第28章 SMTP:简单邮件传送协议_《TCP/IP详解 卷1:协议》_即时通讯网(52im.net) _即时通讯开发者社区!

SMTP服务器地址:一般是 smtp.xxx.com,比如163邮箱是smtp.163.com,qq邮箱是smtp.qq.com。

SMTP协议:通常把处理用户smtp请求(邮件发送请求)的服务器称之为SMTP服务器(邮件发送服务器)。

POP3协议:通常把处理用户pop3请求(邮件接收请求)的服务器称之为POP3服务器(邮件接收服务器)。

二、Java发送邮件

JAVA邮件发送的大致过程是这样的的:
1、构建一个继承自javax.mail.Authenticator的具体类,并重写里面的getPasswordAuthentication()方法。此类是用作登录校验的,以确保你对该邮箱有发送邮件的权利。
2、构建一个properties文件,该文件中存放SMTP服务器地址等参数。
3、通过构建的properties文件和javax.mail.Authenticator具体类来创建一个javax.mail.Session。Session的创建,就相当于登录邮箱一样。剩下的自然就是新建邮件。
4、构建邮件内容,一般是javax.mail.internet.MimeMessage对象,并指定发送人,收信人,主题,内容等等。
5、使用javax.mail.Transport工具类发送邮件。

使用到的jar包:

mail.jar
activation.jar
QQ邮箱需获取相应的权限:

QQ邮箱–>邮箱设置–>账户–>POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务 开启POP3/SMTP服务,然后获取16位授权码(注意不要将授权码泄露,一个账户可以拥有多个授权码)

2.1 Java实现纯文本邮件发送

package org.westos.email;import com.sun.mail.util.MailSSLSocketFactory;import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.security.GeneralSecurityException;
import java.util.Properties;public class SendEamil {public static void main(String[] args) throws MessagingException, GeneralSecurityException {//创建一个配置文件并保存Properties properties = new Properties();properties.setProperty("mail.host","smtp.qq.com");properties.setProperty("mail.transport.protocol","smtp");properties.setProperty("mail.smtp.auth","true");//QQ存在一个特性设置SSL加密MailSSLSocketFactory sf = new MailSSLSocketFactory();sf.setTrustAllHosts(true);properties.put("mail.smtp.ssl.enable", "true");properties.put("mail.smtp.ssl.socketFactory", sf);//创建一个session对象Session session = Session.getDefaultInstance(properties, new Authenticator() {@Overrideprotected PasswordAuthentication getPasswordAuthentication() {return new PasswordAuthentication("619046217@qq.com","16位授权码");}});//开启debug模式session.setDebug(true);//获取连接对象Transport transport = session.getTransport();//连接服务器transport.connect("smtp.qq.com","619046217@qq.com","16位授权码");//创建邮件对象MimeMessage mimeMessage = new MimeMessage(session);//邮件发送人mimeMessage.setFrom(new InternetAddress("619046217@qq.com"));//邮件接收人mimeMessage.setRecipient(Message.RecipientType.TO,new InternetAddress("875203654@qq.com"));//邮件标题mimeMessage.setSubject("Hello Mail");//邮件内容mimeMessage.setContent("我的想法是把代码放进一个循环里","text/html;charset=UTF-8");//发送邮件transport.sendMessage(mimeMessage,mimeMessage.getAllRecipients());//关闭连接transport.close();}
}

2.2Java实现文本图片附件复杂的邮件发送

MIME(多用途互联网邮件扩展类型)

MimeBodyPart类

javax.mail.internet.MimeBodyPart类 表示的是一个MIME消息,它和MimeMessage类一样都是从Part接口继承过来。

MimeMultipart类

javax.mail.internet.MimeMultipart是抽象类 Multipart的实现子类,它用来组合多个MIME消息。一个MimeMultipart对象可以包含多个代表MIME消息的MimeBodyPart对象

package org.westos.email;import com.sun.mail.util.MailSSLSocketFactory;import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.*;
import java.security.GeneralSecurityException;
import java.util.Properties;public class SendComplexEmail {public static void main(String[] args) throws GeneralSecurityException, MessagingException {Properties prop = new Properties();prop.setProperty("mail.host", "smtp.qq.com"); // 设置QQ邮件服务器//prop.setProperty("mail.smtp.port", "25"); // 当使用公司内部邮箱,可以设置端口//prop.setProperty("mail.smtp.host", "smtp.qq.com"); // 当使用公司内部邮箱,可以设置服务器prop.setProperty("mail.transport.protocol", "smtp"); // 邮件发送协议prop.setProperty("mail.smtp.auth", "true"); // 需要验证用户名密码// QQ邮箱设置SSL加密(可以不改)MailSSLSocketFactory sf = new MailSSLSocketFactory();sf.setTrustAllHosts(true);prop.put("mail.smtp.ssl.enable", "true");prop.put("mail.smtp.ssl.socketFactory", sf);//1、创建定义整个应用程序所需的环境信息的 Session 对象Session session = Session.getDefaultInstance(prop, new Authenticator() {@Overrideprotected PasswordAuthentication getPasswordAuthentication() {//传入发件人的姓名和授权码return new PasswordAuthentication("619046217@qq.com","16位授权码");}});//2、通过session获取transport对象Transport transport = session.getTransport();//3、通过transport对象邮箱用户名和授权码连接邮箱服务器transport.connect("smtp.qq.com","619046217@qq.com","16位授权码");//4、创建邮件,传入session对象MimeMessage mimeMessage = complexEmail(session);//5、发送邮件transport.sendMessage(mimeMessage,mimeMessage.getAllRecipients());//6、关闭连接transport.close();}public static MimeMessage complexEmail(Session session) throws MessagingException {//消息的固定信息MimeMessage mimeMessage = new MimeMessage(session);//发件人mimeMessage.setFrom(new InternetAddress("619046217@qq.com"));//收件人mimeMessage.setRecipient(Message.RecipientType.TO,new InternetAddress("619046217@qq.com"));//邮件标题mimeMessage.setSubject("带图片和附件的邮件");//邮件内容//准备图片数据MimeBodyPart image = new MimeBodyPart();DataHandler handler = new DataHandler(new FileDataSource("E:\\IdeaProjects\\WebEmail\\resources\\测试图片.png"));image.setDataHandler(handler);image.setContentID("test.png"); //设置图片id//准备文本MimeBodyPart text = new MimeBodyPart();text.setContent("这是一段文本<img src='cid:test.png'>","text/html;charset=utf-8");//附件MimeBodyPart appendix = new MimeBodyPart();appendix.setDataHandler(new DataHandler(new FileDataSource("E:\\IdeaProjects\\WebEmail\\resources\\测试文件.txt")));appendix.setFileName("test.txt");//拼装邮件正文MimeMultipart mimeMultipart = new MimeMultipart();mimeMultipart.addBodyPart(image);mimeMultipart.addBodyPart(text);mimeMultipart.setSubType("related");//文本和图片内嵌成功//将拼装好的正文内容设置为主体MimeBodyPart contentText = new MimeBodyPart();contentText.setContent(mimeMultipart);//拼接附件MimeMultipart allFile = new MimeMultipart();allFile.addBodyPart(appendix);//附件allFile.addBodyPart(contentText);//正文allFile.setSubType("mixed"); //正文和附件都存在邮件中,所有类型设置为mixed//放到Message消息中mimeMessage.setContent(allFile);mimeMessage.saveChanges();//保存修改return mimeMessage;}
}

2.3 JavaWeb发送邮件(网站注册成功发送提示邮件)

2.3.1 User

package org.westos.mail;public class User {private String name;private String password;private String mail;public User() {}public User(String name, String password, String mail) {this.name = name;this.password = password;this.mail = mail;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getMail() {return mail;}public void setMail(String mail) {this.mail = mail;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", password='" + password + '\'' +", mail='" + mail + '\'' +'}';}
}

2.3.2 Servlet

package org.westos.mail;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class Servlet extends javax.servlet.http.HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request,response);}protected void doGet(HttpServletRequest request, HttpServletResponse response) {//处理前端请求String username = request.getParameter("username");String password = request.getParameter("password");String email = request.getParameter("email");//将信息封装进user对象User user = new User(username, password, email);SendMail sendMail = new SendMail(user);sendMail.start(); //开启线程request.setAttribute("msg","发送成功");try {request.getRequestDispatcher("msg.jsp").forward(request,response);} catch (ServletException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
}

2.3.3 SengMail

package org.westos.mail;import com.sun.mail.util.MailSSLSocketFactory;import javax.mail.*;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.security.GeneralSecurityException;
import java.security.PublicKey;
import java.util.Properties;public class SendMail extends Thread {//发件人信息private String From = "619046217@qq.com";//发件人邮箱private String recipient = "619046217@qq.com";//邮箱密码private String password = "16位授权码";//邮件发送的服务器private String host = "smtp.qq.com";//收件人信息private User user;public SendMail(User user){this.user = user;}@Overridepublic void run() {try {Properties properties = new Properties();properties.setProperty("mail.host","smtp.qq.com");properties.setProperty("mail.transport.protocol","smtp");properties.setProperty("mail.smtp.auth","true");//QQ存在一个特性设置SSL加密MailSSLSocketFactory sf = null;try {sf = new MailSSLSocketFactory();} catch (GeneralSecurityException e) {e.printStackTrace();}sf.setTrustAllHosts(true);properties.put("mail.smtp.ssl.enable", "true");properties.put("mail.smtp.ssl.socketFactory", sf);//创建一个session对象Session session = Session.getDefaultInstance(properties, new Authenticator() {@Overrideprotected PasswordAuthentication getPasswordAuthentication() {return new PasswordAuthentication(recipient,password);}});//开启debug模式session.setDebug(true);//获取连接对象Transport transport = null;try {transport = session.getTransport();} catch (NoSuchProviderException e) {e.printStackTrace();}//连接服务器transport.connect(host,From,password);//创建一个邮件发送对象MimeMessage mimeMessage = new MimeMessage(session);//邮件发送人mimeMessage.setFrom(new InternetAddress(recipient));//邮件接收人mimeMessage.setRecipient(Message.RecipientType.TO,new InternetAddress(user.getMail()));//邮件标题mimeMessage.setSubject("网站注册成功");//邮件内容mimeMessage.setContent("网站注册成功,密码为"+user.getPassword()+",请妥善保管密码","text/html;charset=UTF-8");//发送邮件transport.sendMessage(mimeMessage,mimeMessage.getAllRecipients());transport.close();}catch (Exception e){e.printStackTrace();}}}

2.3.4 register.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>注册页面</title>
</head>
<body><form action="${pageContext.request.contextPath}/a.do" method="post"><p>用户名:<input type="text" name="username" required></p><p>密码:<input type="password" name="password" required></p><p>邮箱:<input type="email" name="email" required></p><p><input type="submit" value="提交"></p>
</form>
</body>
</html>

2.3.5 msg.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body>
${msg}
</body>
</html>

2.3.6 web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><servlet><servlet-name>Servlet</servlet-name><servlet-class>org.westos.mail.Servlet</servlet-class></servlet><servlet-mapping><servlet-name>Servlet</servlet-name><url-pattern>/a.do</url-pattern></servlet-mapping>
</web-app>

可能遇到的问题

1.没有这两个JAR包

mail.jar    Download javax.mail.jar : javax.mail « j « Jar File Download
activation.jar       Download javax.activation-3.0-prelude.jar : javax.activation « j « Jar File Download

下面的报错需要开启debug模式

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

2.

javax.mail.MessagingException: IOException while sending message; nested exception is: javax.activation.UnsupportedDataTypeException: no object DCH for MIME type multipart/mixed;

解决方法,加这个代码

参考链接

jakarta mail - MessagingExceptionIOException while sending message in java? - Stack Overflow

import javax.activation.CommandMap;
import javax.activation.MailcapCommandMap;MailcapCommandMap mailcapCommandMap = new MailcapCommandMap();mailcapCommandMap.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");mailcapCommandMap.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");mailcapCommandMap.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");mailcapCommandMap.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");mailcapCommandMap.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");Thread.currentThread().setContextClassLoader(类名.class.getClassLoader());    

3.

javax.mail.MessagingException: IOException while sending message;nested exception is:java.net.SocketException: Connection reset by peer: socket write error

一般是邮箱对附件大小有限制

QQ和163一般是50M

解决方法1

1.压缩附件或者删掉不必要项,尽可能使附件小于50M;

2.寻找其他附件支持大于50M的邮箱账号来进行发送;一般139邮件的最大附件不超过60M,看下是否满足。

解决方法2

参考 javax.mail.MessagingException: while sending message;Connection reset by peer: socket write error_烤鸭的世界我们不懂的博客-CSDN博客

4.

org.springframework.mail.MailSendException: Failed messages: javax.mail.MessagingException: Exception reading response (java.net.SocketTimeoutException: Read timed out)at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:448) ~[spring-context-support-4.1.0.RELEASE.jar:4.1.0.RELEASE]at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:346) ~[spring-context-support-4.1.0.RELEASE.jar:4.1.0.RELEASE]at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:341) ~[spring-context-support-4.1.0.RELEASE.jar:4.1.0.RELEASE]

解决方式

5.

javax.mail.MessagingException: Could not connect to SMTP host: crmail.crc.com.cn, port: 25, response: -1. 

服务器有问题,可能有个地方被墙了

DEBUG SMTP: IOException while sending, closing, THROW:
java.io.IOException: javax.mail.MessagingException: No MimeBodyPart contentat com.sun.mail.handlers.multipart_mixed.writeTo(multipart_mixed.java:105)at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:889)at javax.activation.DataHandler.writeTo(DataHandler.java:317)at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1485)at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1773)at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1119)at com.etc.email.EmailTest.sendEmailTest(EmailTest.java:104)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)at org.junit.runners.ParentRunner.run(ParentRunner.java:363)at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)at org.junit.runner.JUnitCore.run(JUnitCore.java:137)at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

代码的问题,建议找一个其他正确的

以下这部分参考:

JavaMail邮件发送不成功的那些坑人情况及分析说明 - JackFe - 博客园

6、后台显示邮件发送成功但未收到邮件

问题现象

  使用新浪邮箱发送邮件,尝试两种邮件发送方式,分别是“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发送邮件遭遇的第一个问题,案例都是参考别人原封不动拿过来用的,却发了收不到邮件。换了几个参考案例,问题现象相同。我开始怀疑别人给的案例代码问题,毕竟堂堂的新浪邮箱还不至于这么不靠谱。然后,就是基于这样的判断,我就吃了大亏,一直在分析代码和配置方式,也在各大论坛搜“发送邮件成功却收不到邮件”,发现出现问题的不在少数,而且多半给出的建议是检查代码有没有问题,然后提问的人也没了回复下文,这就导致了很大的误导性。这正是因为这个原因,我也白白地耗了好几天时间,直到最后发现原来原因是这么简单...有时别人的解答能够事半功倍,但是这种依赖性还是不靠谱的,有时自己的排错思路更重要

7、向新浪邮箱发信被退信

问题现象

  平时开发测试,不想用私人常用邮箱,于是注册了搜狐邮箱,并尝试向新浪邮箱发送邮件,不过很快搜狐邮箱收到退信(这种情况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:MX Lookup Tool - Check your DNS MX Records online - MxToolbox 
BlackListAlert:BLACKLISTALERT.ORG - Email Problem ? - Test if your IP or DOMAIN is blacklisted in a spamdatabase

8、向163邮箱发信未收到且也无未退信

问题现象

  通过搜狐邮箱向新浪邮箱发信遭遇退信后,我尝试自己发给自己,正常收到邮件。考虑模拟测试要尽量真实,我改向163邮箱发信,结果出现后台显示发信成功,163邮箱却没收到邮件,但本地邮箱并没收到退信通知。

问题分析

  这说明“后台显示邮件发送成功但未收到邮件”的情况,原因还是多种多样的,不仅可能发件服务器有问题,还可能是收件服务器的问题。收件服务器有的给你退信,有的还收了直接丢弃,真是什么奇葩情况都有,多加注意吧。

9、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 requiredat 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包。

10、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 deniedat 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服务器抽风了,目前我暂时忽略。   当然,如果有分析出是代码问题,也欢迎留言告知分享。(注:后面文章我会将我的代码粘贴出来共享)

11、发信成功后,回应的信息不同

问题现象

  我将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代表邮件发送正常即可。

12.

DATA
421 4.4.5 HL:ICC .For more information, please visit https://feedback.qiye.163.com/bounce/ABFBVSMHL1UjWg5deEB4cQYGBS0%2FeFQnbkxEXUch
DEBUG SMTP: got response code 421, with response: 421 4.4.5 HL:ICC .For more information, please visit https://feedback.qiye.163.com/bounce/ABFBVSMHL1UjWg5deEB4cQYGBS0%2FeFQnbkxEXUchRSET
DEBUG SMTP: EOF: [EOF]
DEBUG SMTP: MessagingException while sending, THROW:
com.sun.mail.smtp.SMTPSendFailedException: 421 4.4.5 HL:ICC .For more information, please visit https://feedback.qiye.163.com/bounce/ABFBVSMHL1UjWg5deEB4cQYGBS0%2FeFQnbkxEXUchat com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:2108)at com.sun.mail.smtp.SMTPTransport.data(SMTPTransport.java:1876)at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1119)at com.etc.email.EmailTest.sendEmailTest(EmailTest.java:104)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)at org.junit.runners.ParentRunner.run(ParentRunner.java:363)at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)at org.junit.runner.JUnitCore.run(JUnitCore.java:137)at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

•421 HL:REP 该IP发送行为异常,存在接收者大量不存在情况,被临时禁止连接。请检查是否有用户发送病毒或者垃圾邮件,并核对发送列表有效性;
•421 HL:ICC 该IP同时并发连接数过大,超过了网易的限制,被临时禁止连接。请检查是否有用户发送病毒或者垃圾邮件,并降低IP并发连接数量;
•421 HL:IFC 该IP短期内发送了大量信件,超过了网易的限制,被临时禁止连接。请检查是否有用户发送病毒或者垃圾邮件,并降低发送频率;
•421 HL:MEP 该IP发送行为异常,存在大量伪造发送域域名行为,被临时禁止连接。请检查是否有用户发送病毒或者垃圾邮件,并使用真实有效的域名发送;

更多错误码的介绍:

  •421 HL:REP 该IP发送行为异常,存在接收者大量不存在情况,被临时禁止连接。请检查是否有用户发送病毒或者垃圾邮件,并核对发送列表有效性;•421 HL:ICC 该IP同时并发连接数过大,超过了网易的限制,被临时禁止连接。请检查是否有用户发送病毒或者垃圾邮件,并降低IP并发连接数量;•421 HL:IFC 该IP短期内发送了大量信件,超过了网易的限制,被临时禁止连接。请检查是否有用户发送病毒或者垃圾邮件,并降低发送频率;•421 HL:MEP 该IP发送行为异常,存在大量伪造发送域域名行为,被临时禁止连接。请检查是否有用户发送病毒或者垃圾邮件,并使用真实有效的域名发送;•450 MI:CEL 发送方出现过多的错误指令。请检查发信程序;•450 MI:DMC 当前连接发送的邮件数量超出限制。请减少每次连接中投递的邮件数量;•450 MI:CCL 发送方发送超出正常的指令数量。请检查发信程序;•450 RP:DRC 当前连接发送的收件人数量超出限制。请控制每次连接投递的邮件数量;•450 RP:CCL 发送方发送超出正常的指令数量。请检查发信程序;•450 DT:RBL 发信IP位于一个或多个RBL里。请参考http://www.rbls.org/关于RBL的相关信息;•450 WM:BLI 该IP不在网易允许的发送地址列表里;•450 WM:BLU 此用户不在网易允许的发信用户列表里;•451 DT:SPM ,please try again 邮件正文带有垃圾邮件特征或发送环境缺乏规范性,被临时拒收。请保持邮件队列,两分钟后重投邮件。需调整邮件内容或优化发送环境;•451 Requested mail action not taken: too much fail authentication 登录失败次数过多,被临时禁止登录。请检查密码与帐号验证设置;•451 RP:CEL 发送方出现过多的错误指令。请检查发信程序;•451 MI:DMC 当前连接发送的邮件数量超出限制。请控制每次连接中投递的邮件数量;•451 MI:SFQ 发信人在15分钟内的发信数量超过限制,请控制发信频率;•451 RP:QRC 发信方短期内累计的收件人数量超过限制,该发件人被临时禁止发信。请降低该用户发信频率;•451 Requested action aborted: local error in processing 系统暂时出现故障,请稍后再次尝试发送;•500 Error: bad syntaxU 发送的smtp命令语法有误;•550 MI:NHD HELO命令不允许为空;•550 MI:IMF 发信人电子邮件地址不合规范。请参考http://www.rfc-editor.org/关于电子邮件规范的定义;•550 MI:SPF 发信IP未被发送域的SPF许可。请参考http://www.openspf.org/关于SPF规范的定义;•550 MI:DMA 该邮件未被发信域的DMARC许可。请参考http://dmarc.org/关于DMARC规范的定义;•550 MI:STC 发件人当天的连接数量超出了限定数量,当天不再接受该发件人的邮件。请控制连接次数;•550 RP:FRL 网易邮箱不开放匿名转发(Open relay);•550 RP:RCL 群发收件人数量超过了限额,请减少每封邮件的收件人数量;•550 RP:TRC 发件人当天内累计的收件人数量超过限制,当天不再接受该发件人的邮件。请降低该用户发信频率;•550 DT:SPM 邮件正文带有很多垃圾邮件特征或发送环境缺乏规范性。需调整邮件内容或优化发送环境;•550 Invalid User 请求的用户不存在;•550 User in blacklist 该用户不被允许给网易用户发信;•550 User suspended 请求的用户处于禁用或者冻结状态;•550 Requested mail action not taken: too much recipient  群发数量超过了限额;•552 Illegal Attachment 不允许发送该类型的附件,包括以.uu .pif .scr .mim .hqx .bhx .cmd .vbs .bat .com .vbe .vb .js .wsh等结尾的附件;•552 Requested mail action aborted: exceeded mailsize limit 发送的信件大小超过了网易邮箱允许接收的最大限制;•553 Requested action not taken: NULL sender is not allowed 不允许发件人为空,请使用真实发件人发送;•553 Requested action not taken: Local user only  SMTP类型的机器只允许发信人是本站用户;•553 Requested action not taken: no smtp MX only  MX类型的机器不允许发信人是本站用户;•553 authentication is required  SMTP需要身份验证,请检查客户端设置;•****554** DT:SPM 发送的邮件内容包含了未被许可的信息,或被系统识别为垃圾邮件。请检查是否有用户发送病毒或者垃圾邮件;**•554 DT:SUM 信封发件人和信头发件人不匹配;•554 IP is rejected, smtp auth error limit exceed 该IP验证失败次数过多,被临时禁止连接。请检查验证信息设置;•554 HL:IHU 发信IP因发送垃圾邮件或存在异常的连接行为,被暂时挂起。请检测发信IP在历史上的发信情况和发信程序是否存在异常;•554 HL:IPB 该IP不在网易允许的发送地址列表里;•554 MI:STC 发件人当天内累计邮件数量超过限制,当天不再接受该发件人的投信。请降低发信频率;•554 MI:SPB 此用户不在网易允许的发信用户列表里;•554 IP in blacklist 该IP不在网易允许的发送地址列表里。

https://blog.csdn.net/wangyanming123/article/details/52734334

可能是同一时间发送次数过多,被拦截了,换个ip或者等一会再试。(用网易的企业邮箱会有这个问题,阿里云的没事)

12参考链接:https://blog.csdn.net/angry_mills/article/details/102475632

参考链接:

Java实现邮件发送_baolingye的博客-CSDN博客_java发送邮件

JAVA实现邮件发送相关推荐

  1. Java Mail 邮件发送(一):入门Demo

    本文首发于简书,Java Mail 邮件发送(一):Demo 上周公司的项目要求开发邮件发送功能.自己在网上跟着教程边学边做了一下午,现在基本开发完成了.由于一个同事也想看下该怎么写,顺便学习下.所以 ...

  2. 用java实现邮件发送验证码

    java实现邮件发送验证码 网易邮箱开通POP3SMTP服务的步骤 java实现邮件发送验证码 建议不要用qq邮箱,我使用qq邮箱直接一直给我报530错误,我一直认为我代码写的有错误或者POP3/SM ...

  3. java实现邮件发送, 抄送及多附件发送

    java实现邮件发送, 抄送及多附件发送 所需的jar包  mailapi.jar和smtp.jar  或  javax-mail-xxx.jar(如javax.mail-1.5.6.jar)  ht ...

  4. 用java实现邮件发送

    电子邮件 1.基础知识铺垫 要在网络上实现邮件功能,必须要有专门的邮件服务器. 这些邮件服务器类似于现实生活中的邮局,它主要负责接收用户投递过的邮件,并把邮件投递到邮件接收者的电子邮箱中. SMTP服 ...

  5. [Java工具] 邮件发送工具

    注册邮箱 去163邮箱(或其他邮箱)注册一个邮箱,并开启SMTP授权码. 程序 需要注意的是,由于阿里云服务器不让使用默认的25端口,所以会出现Windows下测试发送邮件成功,Linux服务器下发送 ...

  6. 【Java EE 学习 21 下】【使用java实现邮件发送、邮件验证】

    一.邮件发送 1.邮件发送使用SMTP协议或者IMAP协议,这里使用SMTP协议演示. SMTP协议使用的端口号:25 rfc821详细记载了该协议的相关信息 (1)使用telnet发送邮件(使用12 ...

  7. java实现邮件发送_基于JavaMail的Java实现简单邮件发送功能

    电子邮件的应用非常广泛,例如在某网站注册了一个账户,自动发送一封欢迎邮件,通过邮件找回密码,自动批量发送活动信息等.但这些应用不可能和我们自己平时发邮件一样,先打开浏览器,登录邮箱,创建邮件再发送.本 ...

  8. Java实现邮件发送 超详细!!!(以QQ邮箱个人版和企业版为例)

    Java实现发送邮件 超详细!!!(以QQ邮箱个人版和企业版为例) 文章目录 Java实现发送邮件 超详细!!!(以QQ邮箱个人版和企业版为例) 个人邮箱示例 配置依赖 简单了解涉及的两个传输协议 Q ...

  9. java实现邮件发送共鞥_Java实现复杂邮件发送功能(基于JavaMail)的实例

    这篇文章主要为大家详细介绍了基于JavaMail的Java实现复杂邮件发送功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 上一篇文章 基于 JavaMail 的 Java 邮件发送:简单邮件发 ...

  10. java 异步邮件发送_java异步发送邮件

    其中textTemplate和textTemplate2是spring注入的. package com.ucenter.service; import java.util.concurrent.Exe ...

最新文章

  1. R语言构建logistic回归模型:WVPlots包PRTPlot函数可视化获取logistic回归模型的最优阈值、优化(precision、enrichment)和recall之间的折衷
  2. R多变量正态性检验(Multivariate Normality Tests)
  3. AI算法透明不是必须,黑箱和可解释性可简化为优化问题
  4. php查询mysql并缓存到redis
  5. java consumer.poll_kafka消费者API consumer.poll()没有错误,没有异常,只是阻止
  6. django无法生成自定义表(mysql)
  7. Redis实现消息队列和订阅发布模式
  8. 计算机网络 故障处理,计算机网络通讯技术故障分析与处理
  9. pom文件各标签解释
  10. 常用无线通信协议Zigbee、bluetooth、wifi比较
  11. LiveData setValue和postValue的区别及详解
  12. 炫酷好玩好用的卫星全景地图
  13. 《SteamVR实战之PMCore》(Yanlz+Unity+XR+SteamVR+VR+AR+MR+Valve+Oculus+立钻哥哥+==)
  14. 【DOORS】如何基于DOORS实施需求管理
  15. 经验之谈:做好淘宝客的一些经验秘籍
  16. 深度Linux安装火狐,deepin或Ubuntu安装最新版Firefox,并设置去掉标题栏
  17. iphone icloud无法载入储存空间信息
  18. 0x5085170C (ucrtbased.dll)处(位于 Project1.exe 中)引发的异常: 0xC0000005: 读取位置 0x0000001A 时发生访问冲突。
  19. NBA表格_python告诉你关于NBA得分王中一些有趣的数据
  20. 腾讯云API与国家气象局API获取实时天气

热门文章

  1. 线性表(单链表)—图书管理系统 c语言版
  2. c语言11章谭浩强,谭浩强 C语言 第11章 结构体.ppt
  3. android tv 蓝牙服务_Android TV Remote Service
  4. Python帮助文档的查看方式——Python初学者必看
  5. Java中常见的八种数据结构
  6. 吴恩达机器学习视频笔记——简单知识背景
  7. Docker游戏Dos小游戏,一个web版的dos游戏库
  8. VMD如何确定分解层数(一):最优变分模态分解(OVMD)---VMD分解的基础上确定分解层数和更新步长
  9. eda多功能数字钟课程设计_适用多功能数字钟(EDA技术课程设计)
  10. qt使用QProcess实现进程通信