Java发送邮件(一)之JavaMail
- 前言
- 一、什么是SMTP、POP3、IMAP?
- 二、利用JavaMail发送邮件
- 2.1 引入依赖:
- 2.2 设置发件人邮件的SMTP服务
- 2.3 API使用
- 2.4 API使用时的问题
- 2.4.1 如何设置多个收件人(抄送人)?
- 2.4.2 RecipientType的类型有哪些?分别代表什么?
- 2.4.3 如何发送带格式的邮件,比如html?
- 2.4.4 邮件发送时乱码怎么办?
- 2.4.5 发送邮件时报错java.lang.ClassNotFoundException: com.sun.mail.util.MailLogger
- 2.4.6 发送邮件时报错com.sun.mail.smtp.SMTPSenderFailedException: 503 Error: need EHLO and AUTH first
- 2.4.7 设置邮件的Properties属性 有哪些?分别代表什么意思?
- Reference
前言
本文将讲述如何利用原生JavaMail发送邮件,如果需要看如何利用Spring来实现邮件发送,请参考我的另外一篇博客《Java发送邮件(二)之Spring》,不过Spring其实也是基于JavaMail来做的,所以还是有必要先了解一下JavaMail的一些基本概念和操作。
一、什么是SMTP、POP3、IMAP?
学习Java发送邮件,必然会涉及到的一个术语就是SMTP,而且在邮箱中设置SMTP的时候我们还会看到另外两个术语:POP3和IMAP。那什么是SMTP、POP3、IMAP呢?
简单的说,这三个都是邮件收发相关的三种协议。
- SMTP:全称是“Simple Mail Transfer Protocol”,简单邮件传输协议,它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。用于发送电子邮件的传输协议;
- POP3:全称是"Post Office Protocol 3",是邮局协议的第3个版本,它规定怎样将个人计算机连接到Internet的邮件服务器和下载电子邮件的电子协议。用于接收电子邮件的标准协议;
- IMAP:全称是"Internet Mail Access Protocol",即交互式邮件存取协议,它是跟POP3类似邮件访问标准协议之一。不同的是,开启了IMAP后,您在电子邮件客户端收取的邮件仍然保留在服务器上,同时在客户端上的操作都会反馈到服务器上,如:删除邮件,标记已读等,服务器上的邮件也会做相应的动作,是POP3的替代协议。
二、利用JavaMail发送邮件
JavaMail是Oracle官方提供的一组API库,并没有包含在标准的JDK中,使用时需要我们自己引入依赖,github地址:https://github.com/javaee/javamail。官方提供的这个库能实现对邮件的各种操作,如果感兴趣的可以参考官方提供的使用demo和指导手册详细研究,我们今天仅通过发送邮件这个动作来了解一下这个类库的基本使用。
2.1 引入依赖:
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
JavaMail最新版为1.6.2,这里使用1.4.7是为了方便测试,具体使用1.6.2的问题在后面会提到。
2.2 设置发件人邮件的SMTP服务
以QQ邮箱为例,我们进入邮箱后点击设置 -> 账户,开启SMTP的开关,以及按照操作提示获取SMTP认证的授权码即可。
2.3 API使用
首先,邮件有几个关键要素我们需要掌握,分别是:
- 发件人
- 收件人
- 抄送人
- 密送人
- 邮件主题
- 邮件附件
- 邮件正文
在了解了这些因素之后,自然我们在使用API的时候也是针对设置这些因素来展开的,具体有以下步骤:
(1)设置邮件服务器的一些基本设置(包括邮件SMTP服务器地址,SMTP认证所需要的账号和授权码);
(2)设置发件人、收件人、抄(密)送人
(3)设置邮件主题和正文
(4)有附件的情况设置附件(可选)
接下来我们将按照这个步骤写示例代码:
public static void main(String[] args) throws MessagingException {
// 1. 初始化配置
Properties properties = initProps();
// 2. 通过配置获取session
Session session = Session.getInstance(properties);
session.setDebug(true);//debug时控制台能展示更多的log
// 3.创建邮件
MimeMessage msg = new MimeMessage(session);
// 设置发件人
String from = "fajianren@qq.com";
// QQ邮箱采用的是SMTP授权码认证
String authorizedCode = "wmz******jf";
msg.setFrom(new InternetAddress(from));
// 设置收件人
String recipient = "shoujianren@qq.com";
InternetAddress[] toAddrs = {new InternetAddress(recipient)};
msg.setRecipients(Message.RecipientType.TO, toAddrs);
// 也可以使用下面这个方法这是收件人(1.6版本可以直接使用收件人的地址字符串)
//msg.setRecipients(Message.RecipientType.TO, recipient);
// 设置抄送人,如果是密送,类型使用Message.RecipientType.BCC,多人与上方同理
msg.setRecipients(Message.RecipientType.CC, recipient);
// 设置邮件主题,如果主题中存在中文,要使用支持的字符集
msg.setSubject("JavaMail邮件测试","UTF-8");
// 设置发送时间,这个时间可以随意设置,用于显示发送时间
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_MONTH,-1);
Date date = calendar.getTime();
msg.setSentDate(date);
// 设置发送正文,同样要指定字符集,除非全英文
msg.setText("这是一个测试邮件;\n另一行<font style='color:blue;'>蓝色的字体</font>","UTF-8", "html");
// 4. 邮件发送
Transport transport = session.getTransport();
// 连接SMTP认证
transport.connect(from, authorizedCode);
// 通过Transport对象发送邮件
transport.sendMessage(msg,msg.getAllRecipients());
}
/**
* 设置的基础属性有哪些?
* 可以参考官方的Java Doc,地址:https://javaee.github.io/javamail/docs/api/
* 分别在
* com.sun.mail.smtp
* com.sun.mail.imap
* com.sun.mail.pop3
* 3个包级的文档注释中的Description部分有列表展示了每个参数的含义
*/
private static Properties initProps() {
Properties properties = new Properties();
properties.put("mail.transport.protocol","smtp");
// 发件人邮箱的smtp服务器地址
properties.put("mail.smtp.host","smtp.qq.com");
// smtp服务器端口
properties.put("mail.smtp.port","25");
properties.put("mail.debug", "true");
properties.put("mail.smtp.auth","true");
return properties;
}
2.4 API使用时的问题
2.4.1 如何设置多个收件人(抄送人)?
// 如果有多个收件人,可使用addRecipients方法添加
msg.addRecipients(Message.RecipientType.TO, recipient);
// 或者在setRecipients时全部设置进去.setRecipients方法接收的是一个Address[]数组
2.4.2 RecipientType的类型有哪些?分别代表什么?
RecipientType.TO 收件人
RecipientType.C 抄送人
RecipientType.BC 密送人
2.4.3 如何发送带格式的邮件,比如html?
// MimeMessage的setText有3个重载方法
// setText(String text) 发送普通文本邮件
msg.setText("Hello JavaMail");
// setText(String text, String charset)发送普通文本邮件,指定字符集使得邮件内容不仅局限于英文
msg.setText("你好,JavaMail", "UTF-8");
// setText(String text, String charset, String subtype) 发送指定类型的邮件,类型根据subtype变化
msg.setText("<font style='color:red;'>你好</font>,JavaMail!", "UTF-8","html");
2.4.4 邮件发送时乱码怎么办?
见2.4.3设置好字符集。
2.4.5 发送邮件时报错java.lang.ClassNotFoundException: com.sun.mail.util.MailLogger
出现这个错误一般是因为使用了1.6及以上的版本,我们来看一下1.6版本的maven坐标
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
<version>1.6.1</version>
</dependency>
MailLogger是JavaMail的一部分,包含在Java EE环境里面,但是不包含在Java SE环境里面,出现这个错误很大的原因是在SE环境里面测试邮件的发送;javax.mail-api只适合编译,但是如果你实在要运行代码,必须完全实现JavaMail, 这也是为什么前面提到用1.4.7版本做测试。
2.4.6 发送邮件时报错com.sun.mail.smtp.SMTPSenderFailedException: 503 Error: need EHLO and AUTH first
从字面意思很容易看出来是因为没有设置认证参数。那么解决问题的办法就是设置认证参数。设置认证参数除了上面demo中的通过transport.connect(username,password)方法认证以外,还可以通过以下设置Authenticator对象的方式进行认证。
// 创建一个密码认证
Authenticator authenticator = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("fajianren@qq.com","wm*******jf");
}
};
// 在使用时可以设置进session中
Session session = Session.getInstance(props, authenticator);
// 省略部分代码.......
// 然后在发送邮件的时候就不需要通过transport.connect(username,password)来认证了
// 直接使用
Transport.send(msg,msg.getAllRecipients());
2.4.7 设置邮件的Properties属性 有哪些?分别代表什么意思?
具体含义参见官方Java Doc,地址:https://javaee.github.io/javamail/docs/api/
官方分别在以下三个包级文档的Description中有三张列表,展示了所有的设置参数的key以及含义
- com.sun.mail.smtp
- com.sun.mail.imap
- com.sun.mail.pop3
Reference
http://help.163.com/09/1223/14/5R7P6CJ600753VB8.html
https://javaee.github.io/javamail/docs/api/
https://github.com/javaee/javamail