需求:
每月1日发送邮件,使用JavaEmail实现
常见的邮件协议包括:
SMTP: 简单邮件传输协议,用于发送电子邮件的传输协议。(默认端口25),邮件客户端和SMTP邮件服务器之间通信规则。
POP/ POP3: 用于接收电子邮件的标准协议。(默认端口110),把存储在POP协议邮件服务器的邮件下载到用户计算机中,但不能对邮件进行在线操作。
IMAP: 互联网消息访问协议,是POP3的替代协议。(默认端口143),可以通过客户端直接对服务器上的邮件在线操作。
这三种协议都有对应的SSL加密传输的协议,分别是SMTPS、POP3S和IMAPS。
JavaMail的关键对象:
1. Properties
属性 | 类型 | 说明 |
mail.smtp.host | string | smtp服务器地址 |
mail.smtp.port | int | smtp服务器端口,默认25 |
mail.smtp.auth | boolean | smtp服务器是否需要用户认证,默认false |
mail.smtp.user | string | smtp默认的登录用户名 |
mail.smtp.from | string | 默认的邮件发送源地址 |
mail.smtp.socketFactory.class | String | 必须实现javax.net.SocketFactory接口 |
mail.smtp.socketFactory.port | int | 指定socket工厂类所用的端口号 |
mail.smtp.socketFactory.fallback | boolean | 设定为true时,当使用指定的socket类创建socket失败后,将使用java.net.Socket创建socket,默认为true |
mail.smtp.timeout | int | 连接超时时间,单位为ms,默认为永不超时 |
2.Session: 会话对象, 是一堆配置信息的集合。
3.Transport和Store: 传输和存储。
pom依赖:
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
<version>1.6.0</version>
</dependency>
结果本地测试启动时报了如下错误:
java.lang.ClassNotFoundException: com.sun.mail.util.MailLogger
原因:
MailLogger --是JavaMail的一部分,包含在Java EE环境里面,但是不包含在Java SE环境里面,出现这个错误很大的原因是在SE环境里面测试邮件的发送;
javax.mail-api只适合编译,但是如果你实在要运行代码,必须完全实现JavaMail
修改pom依赖:
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
相关链接:
线上生产环境的pom依赖:
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.5</version >
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.5.4</version>
</dependency>
发送邮件:
一、封装工具类
在发送邮件之前,每次都会创建Session连接,这里可以定义一个JavaMailUtils工具类,每次创建连接时,只需要调用createSession()方法,不必频繁写重复代码了。(看业务需求 封不封装都可)
@Component
public class JavaEmailUtils {
/**
* 创建Session连接
* @return
*/
public static Session createSession() {
//服务器地址
String smtp ="smtp.163.com";
//发件人的邮箱
String userName = "xxx.@163.com";
//发件人密码 | 授权码
String password = "xxxxxxx";
//SSL链接端口
String emailPort = "465";
Properties props = new Properties();
// 是否打开验证:只能设置true,必须打开
props.setProperty("mail.smtp.auth", "true");
//stmp协议
props.setProperty("mail.transport.protocol", "smtp");
// 使用JSSE的SSL
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
// 只处理SSL的连接,对于非SSL的连接不做处理
props.put("mail.smtp.socketFactory.fallback", "false");
// smtp服务器地址
props.put("mail.smtp.host", smtp);
props.put("mail.smtp.port",emailPort);
props.put("mail.smtp.socketFactory.port", emailPort);
props.put("mail.smtp.ssl.enable", true);
props.put("mail.smtp.starttls.enable","true");
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
// TODO Auto-generated method stub
return new PasswordAuthentication(userName, password);
}
});
session.setDebug(true);
return session;
}
}
封装工具类参考链接:
网易邮箱获取授权码参考链接:
二、创建邮件(不使用封装工具类进行邮件的发送)
public ResultVO sendFjEmail(GsbSendEmail gsbSendEmail, String emailAccounts, String emailAuthorizationCode, String emailPort, String title, String content) {
try {
// 1. 创建一封邮件
Properties props = new Properties();
// 是否打开验证:只能设置true,必须打开
props.setProperty("mail.smtp.auth", "true");
//stmp协议
props.setProperty("mail.transport.protocol", "smtp");
//smtp协议
String smtp = "smtp.163.com";
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");// 使用JSSE的SSL
props.put("mail.smtp.socketFactory.fallback", "false"); // 只处理SSL的连接,对于非SSL的连接不做处理
// 设置主机地址 smtp.qq.com smtp.126.com smtp.163.com
props.put("mail.smtp.port", emailPort);
props.put("mail.smtp.socketFactory.port", emailPort);
props.put("mail.smtp.ssl.enable", true);
props.put("mail.smtp.host", smtp);// smtp服务器地址
// 用于连接邮件服务器的参数配置(发送邮件时才需要用到)
// 根据参数配置,创建会话对象(为了发送邮件准备的)
Session session = Session.getInstance(props);
session.setDebug(true);
//创建邮件对象
Message msg = new MimeMessage(session);
//Subject: 邮件主题
msg.setSubject(title);
//发件人邮箱(我的163邮箱)
msg.setFrom(new InternetAddress(emailAccounts));
//收件人邮箱(我的网易云邮箱) 可增加收件人邮箱
msg.setRecipient(Message.RecipientType.TO, new InternetAddress(“邮箱”));
//创建附件“节点”
MimeBodyPart attachment = new MimeBodyPart();
// 读取本地文件
// 模板地址
String filePath = "src" + File.separator + "main" + File.separator + "resources" + File.separator + "template" + File.separator + "xxx.docx";
DataHandler dh2 = new DataHandler(new FileDataSource(filePath));
// 将附件数据添加到“节点”
attachment.setDataHandler(dh2);
// 设置附件的文件名(需要编码)
attachment.setFileName(MimeUtility.encodeText(dh2.getName()));
//正文 将文本封装成一个节点
MimeBodyPart body = new MimeBodyPart();
body.setContent(content, "text/html;charset=utf-8");
//设置文本和附件的关系
Multipart msgPart = new MimeMultipart();
msgPart.addBodyPart(body);
// msgPart.addBodyPart(attachment);
//Content: 邮件正文(可以使用html标签)设置整个邮件的关系(将最终的混合“节点”作为邮件的内容添加到邮件对象)
msg.setContent(msgPart);
//保存前面的设置(邮件生成的最后一步)
msg.saveChanges();
Transport transport = session.getTransport();
transport.connect(emailAccounts, emailAuthorizationCode);//发件人邮箱,授权码(可以在邮箱设置中获取到授权码的信息)
transport.sendMessage(msg, msg.getAllRecipients());
transport.close();
//todo 邮件发送成功,记录日志信息
setLogger(gsbSendEmail,"1","邮件发送成功!");
return new ResultVO().addData("data", "OK");
} catch (Exception e) {
// TODO: 邮件发送失败,记录日志信息
setLogger(gsbSendEmail,"0",e.toString());
return new ResultVO("发送邮箱失败!请联系管理员进行排查");
}
}
邮箱验证规则:
需要满足的验证逻辑:
- @之前必须有内容且只能是字母(大小写)、数字、下划线(_)、减号(-)、点(.)
- @和最后一个点(.)之间必须有内容且只能是字母(大小写)、数字、点(.)、减号(-),且两个点不能挨着
- 最后一个点(.)之后必须有内容且内容只能是字母(大小写)、数字且长度为大于等于2个字节,小于等于6个字节
邮箱验证的正则表达式:
^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$