首先,附上官网文档,请自行查阅:
https://docs.oracle.com/javaee/7/api/javax/mail/package-summary.html
常用邮箱服务器以及对应端口:
sina.com:
POP3服务器地址:pop3.sina.com.cn(端口:110)
SMTP服务器地址:smtp.sina.com.cn(端口:25)
sinaVIP:
POP3服务器:pop3.vip.sina.com (端口:110)
SMTP服务器:smtp.vip.sina.com (端口:25)
sohu.com:
POP3服务器地址:pop3.sohu.com(端口:110)
SMTP服务器地址:smtp.sohu.com(端口:25)
126邮箱:
POP3服务器地址:pop.126.com(端口:110)
SMTP服务器地址:smtp.126.com(端口:25)
139邮箱:
POP3服务器地址:POP.139.com(端口:110)
SMTP服务器地址:SMTP.139.com(端口:25)
163.com:
POP3服务器地址:pop.163.com(端口:110)
SMTP服务器地址:smtp.163.com(端口:25)
QQ邮箱
POP3服务器地址:pop.qq.com(端口:110)
SMTP服务器地址:smtp.qq.com (端口:25)
QQ企业邮箱
POP3服务器地址:pop.exmail.qq.com (SSL启用 端口:995)
SMTP服务器地址:smtp.exmail.qq.com(SSL启用 端口:587/465)
yahoo.com:
POP3服务器地址:pop.mail.yahoo.com
SMTP服务器地址:smtp.mail.yahoo.com
yahoo.com.cn:
POP3服务器地址:pop.mail.yahoo.com.cn(端口:995)
SMTP服务器地址:smtp.mail.yahoo.com.cn(端口:587
HotMail
POP3服务器地址:pop3.live.com (端口:995)
SMTP服务器地址:smtp.live.com (端口:587)
gmail(google.com)
POP3服务器地址:pop.gmail.com(SSL启用 端口:995)
SMTP服务器地址:smtp.gmail.com(SSL启用 端口:587)
263.net:
POP3服务器地址:pop3.263.net(端口:110)
SMTP服务器地址:smtp.263.net(端口:25)
263.net.cn:
POP3服务器地址:pop.263.net.cn(端口:110)
SMTP服务器地址:smtp.263.net.cn(端口:25)
x263.net:
POP3服务器地址:pop.x263.net(端口:110)
SMTP服务器地址:smtp.x263.net(端口:25)
21cn.com:
POP3服务器地址:pop.21cn.com(端口:110)
SMTP服务器地址:smtp.21cn.com(端口:25)
Foxmail:
POP3服务器地址:POP.foxmail.com(端口:110)
SMTP服务器地址:SMTP.foxmail.com(端口:25)
china.com:
POP3服务器地址:pop.china.com(端口:110)
SMTP服务器地址:smtp.china.com(端口:25)
tom.com:
POP3服务器地址:pop.tom.com(端口:110)
SMTP服务器地址:smtp.tom.com(端口:25)
etang.com:
POP3服务器地址:pop.etang.com
SMTP服务器地址:smtp.etang.com
邮件的发送过程大致如下:
创建一个 Session 对象。
Session 对象创建一个 Transport 对象 /Store 对象,用来发送 / 保存邮件。
Transport 对象 /Store 对象连接邮件服务器。
Transport 对象 /Store 对象创建一个 Message 对象 ( 也就是邮件内容 ) 。
Transport 对象发送邮件; Store 对象获取邮箱的邮件。
发送文本邮件最简代码,官方文档给出的如下:
//配置文件
Properties props = new Properties();
//设置邮箱服务器,有对应的默认端口
props.put("mail.smtp.host", "my-mail-server");
//获取一个邮箱session实例
Session session = Session.getInstance(props, null);
try {
//邮件发送工具类参数对象
MimeMessage msg = new MimeMessage(session);
//设置发件人信息
msg.setFrom("me@example.com");
//设置收件人信息
msg.setRecipients(Message.RecipientType.TO,
"you@example.com");
//设置邮件主题
msg.setSubject("JavaMail hello world example");
//设置邮件时间
msg.setSentDate(new Date());
//设置邮件内容
msg.setText("Hello, world!\n");
//发送邮件,验证邮箱账号和密码
Transport.send(msg, "me@example.com", "my-password");
} catch (MessagingException mex) {
System.out.println("send failed, exception: " + mex);
}
以上,就可以完成一个简单的邮件发送。
接下来,我们做一下优化,使其能够成为易于维护的工具类。
先建一个maven工程,pom.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>spring-boot</groupId>
<artifactId>spring-study</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--spring-boot-starter-test 起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>LATEST</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.29</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
我们最主要是添加 spring-boot-starter-mail 的起步依赖来实现邮件发送的功能。
MailAuthenticator ,用于用户登录认证
package demo.mail;
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
public class MailAuthenticator extends Authenticator {
/**
* 用户名
*/
private String userName;
/**
* 密码
*/
private String userPass;
public MailAuthenticator() {
}
public MailAuthenticator(String userName, String userPass) {
this.userName = userName;
this.userPass = userPass;
}
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(userName, userPass);
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPass() {
return userPass;
}
public void setUserPass(String userPass) {
this.userPass = userPass;
}
@Override
public String toString() {
return "MailAuthenticator{" +
"userName='" + userName + '\'' +
", userPass='" + userPass + '\'' +
'}';
}
}
MailBean,邮件发送bean
package demo.mail;
import java.util.List;
public class MailBean {
/**
* 发件人地址
*/
private String fromAddress;
/**
* 收件人地址
*/
private String toAddress;
/**
* 邮箱用户名
*/
private String userName;
/**
* 邮箱用户名密码
*/
private String userPassword;
/**
* 多个收件人
*/
private List<String> recipients;
/**
* 邮件主题
*/
private String subject;
/**
* 邮件内容
*/
private MailContent content;
public String getFromAddress() {
return fromAddress;
}
public void setFromAddress(String fromAddress) {
this.fromAddress = fromAddress;
}
public String getToAddress() {
return toAddress;
}
public void setToAddress(String toAddress) {
this.toAddress = toAddress;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public List<String> getRecipients() {
return recipients;
}
public void setRecipients(List<String> recipients) {
this.recipients = recipients;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public MailContent getContent() {
return content;
}
public void setContent(MailContent content) {
this.content = content;
}
@Override
public String toString() {
return "MailBean{" +
"fromAddress='" + fromAddress + '\'' +
", toAddress='" + toAddress + '\'' +
", userName='" + userName + '\'' +
", userPassword='" + userPassword + '\'' +
", recipients=" + recipients +
", subject='" + subject + '\'' +
", content=" + content +
'}';
}
}
Mail配置常量
package demo.mail;
public class MailConstant {
/**
* smtp 服务器
*/
public static final String MAIL_SMTP_HOST = "mail.smtp.host";
/**
* smtp服务器的端口
*/
public static final String MAIL_SMTP_PORT = "mail.smtp.port";
/**
* 如果为true,STARTTLS则在发出任何登录命令之前,启用命令(如果服务器支持)将连接切换到TLS保护的连接。
* 请注意,必须配置适当得信任存储,以便客户端信任服务器得证书。默认为false
*/
public static final String MAIL_SMTP_STARTTLS_ENABLE = "mail.smtp.starttls.enable";
/**
* 如果为true,则尝试使用AUTH命令认证用户。默认为false.
*/
public static final String MAIL_SMTP_AUTH = "mail.smtp.auth";
/**
* 指定使用指定套接字工厂时要连接的端口。如果未设置,将使用默认端口。
*/
public static final String MAIL_SMTP_SOCKETFACTORY_PORT = "mail.smtp.socketFactory.port";
/**
* 如果设置为true,则无法使用指定的套接字工厂类创建套接字将导致使用java.net.Socket该类创建套接字。默认为true.
*/
public static final String MAIL_SMTP_SOCKETFACTORY_FALLBACK = "mail.smtp.socketFactory.fallback";
/**
* Transport对象才会向SMTP服务器提交用户认证信息
*/
public static final String MAIL_TRANSPORT_PROTOCOL = "mail.transport.protocol";
/**
* 发件人地址
*/
public static final String MAIL_FROM = "mail.from";
/**
* ssl 被smtp认证
*/
public static final String MAIL_SMTP_SSL_TRUST = "mail.smtp.ssl.trust";
/**
* 用户名
*/
public static final String MAIL_USERNAME = "mail.username";
/**
* 密码
*/
public static final String MAIL_CRYPTOGRAM = "mail.password";
/**
* 私有构造器,坏味道
*/
private MailConstant() {
//do nothing
}
}
MailContent,用于存储邮件内容:
package demo.mail;
public class MailContent {
/**
* 邮件主题
*/
private String subject;
/**
* 内容时间
*/
private String date;
/**
* 内容
*/
private String content;
public MailContent() {
}
public MailContent(String subject, String date, String content) {
this.subject = subject;
this.date = date;
this.content = content;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "MailContent{" +
"subject='" + subject + '\'' +
", date='" + date + '\'' +
", content='" + content + '\'' +
'}';
}
}
MailHtml,将邮件内容转换为Html形式
package demo.mail;
public class MailHtml {
public static String getMailHtml(String date,String sub,String content){
StringBuilder sb = new StringBuilder();
sb.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">")
.append("<html>")
.append("<head>")
.append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">")
.append("<title>邮件</title>")
.append("<style type=\"text/css\">")
.append("table{width:100%;height:100%;border-collapse:collapse;border:none;}")
.append("table td{border:solid gray 1px;}")
.append(".td_1{width:20%;text-align:center;background-color:#cce8cf;}")
.append("</style>")
.append("</head>")
.append("<body>")
.append("<table>")
.append("<tr style='height:15%;'><td class=\"td_1\">时间</td><td>"+date+"</td></tr>")
.append("<tr style='height:15%;'><td class=\"td_1\">标题</td><td>"+sub+"</td></tr>")
.append("<tr><td class=\"td_1\">内容</td><td>"+content+"</td></tr>")
.append("</table>")
.append("</body>")
.append("</html>");
return sb.toString();
}
private MailHtml() {
throw new IllegalAccessError("MailHtml class");
}
}
MailProperties,用于获取邮件配置文件信息
package demo.mail;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ResourceBundle;
public class MailProperties {
private static Logger logger = LoggerFactory.getLogger(MailProperties.class);
private static final String BONDEL_NAME = "mail";
private static final ResourceBundle bundel = ResourceBundle.getBundle(BONDEL_NAME);
public static String getValue(String key) {
//参数校验
if (StringUtils.isBlank(key)) {
System.out.println("发生了未知异常!");
}
String value = null;
try {
value = bundel.getString(StringUtils.trim(key));
} catch (Exception e) {
logger.warn(String.format("value not existed: %s", key), e);
}
return StringUtils.isBlank(value) ? StringUtils.EMPTY : value;
}
}
MailSend,邮件发送类:
package demo.mail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.mail.*;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Date;
import java.util.List;
import java.util.Properties;
public class MailSend {
private static final Logger logger = LoggerFactory.getLogger(MailSend.class);
/**
* 发送邮件的props 文件
*/
private static Properties props;
/**
* 邮件登录 权限验证
*/
private static MailAuthenticator authenticator;
/**
* 邮件服务器session
*/
private static Session session;
/**
* 发送邮件 工具
*/
private static Transport transport;
/**
* 邮件附件(目前还不支持附件上传的功能)
*/
private static Multipart multipart;
/**
* 初始化
*
*/
static {
// 初始化props
props = new Properties();
props.put(MailConstant.MAIL_SMTP_HOST, MailProperties.getValue(MailConstant.MAIL_SMTP_HOST));
props.put(MailConstant.MAIL_SMTP_PORT, MailProperties.getValue(MailConstant.MAIL_SMTP_PORT));
props.put(MailConstant.MAIL_SMTP_STARTTLS_ENABLE, MailProperties.getValue(MailConstant.MAIL_SMTP_STARTTLS_ENABLE));
props.put(MailConstant.MAIL_SMTP_AUTH, MailProperties.getValue(MailConstant.MAIL_SMTP_AUTH));
props.put(MailConstant.MAIL_SMTP_SOCKETFACTORY_PORT, MailProperties.getValue(MailConstant.MAIL_SMTP_SOCKETFACTORY_PORT));
props.put(MailConstant.MAIL_SMTP_SOCKETFACTORY_FALLBACK, MailProperties.getValue(MailConstant.MAIL_SMTP_SOCKETFACTORY_FALLBACK));
props.put(MailConstant.MAIL_TRANSPORT_PROTOCOL, MailProperties.getValue(MailConstant.MAIL_TRANSPORT_PROTOCOL));
props.put(MailConstant.MAIL_FROM, MailProperties.getValue(MailConstant.MAIL_FROM));
props.put(MailConstant.MAIL_SMTP_SSL_TRUST, MailProperties.getValue(MailConstant.MAIL_SMTP_SSL_TRUST));
// 验证
authenticator = new MailAuthenticator(MailProperties.getValue(MailConstant.MAIL_USERNAME),
MailProperties.getValue(MailConstant.MAIL_CRYPTOGRAM));
// 创建session
session = Session.getDefaultInstance(props, authenticator);
}
/**
* 群发邮件
*
* @param recipients 收件人们
* @param subject 主题
* @param content 内容
* @throws AddressException
* @throws MessagingException
*/
@SuppressWarnings("static-access")
protected static void send(List<String> recipients, String subject, MailContent content) {
try {
// 创建mime类型邮件
final MimeMessage message = new MimeMessage(session);
// 设置发信人
message.setFrom(new InternetAddress(authenticator.getUserName()));
// 设置收件人们
final int num = recipients.size();
InternetAddress[] addresses = new InternetAddress[num];
for (int i = 0; i < num; i++) {
addresses[i] = new InternetAddress(recipients.get(i));
}
message.setRecipients(Message.RecipientType.TO, addresses);
// 设置主题
message.setSubject(subject);
// 设置邮件内容
message.setContent(MailHtml.getMailHtml(content.getDate(), content.getSubject(), content.getContent()),
"text/html;charset=utf-8");
// 发送时间
message.setSentDate(new Date());
message.saveChanges();
// 发送
logger.info("===protocol is ============" + props.get(MailConstant.MAIL_TRANSPORT_PROTOCOL) );
transport = session.getTransport(((String) props.get(MailConstant.MAIL_TRANSPORT_PROTOCOL)).trim());
// 真正的连接邮件服务器并进行身份验证
transport.connect((String.valueOf(props.get(MailConstant.MAIL_SMTP_HOST)).trim()),
Integer.parseInt(String.valueOf(props.get(MailConstant.MAIL_SMTP_PORT))), authenticator.getUserName(),
authenticator.getUserPass());
transport.send(message);
} catch (Exception e) {
logger.error("mailsend send error : ", e);
} finally {
try {
transport.close();
} catch (MessagingException e) {
logger.error("mailsend send close error : ", e);
}
}
}
}
SendMailThread,用于控制最大并发
package demo.mail;
public class SendMailThread implements Runnable{
private MailBean mailBean;
public SendMailThread(MailBean mailBean) {
this.mailBean = mailBean;
}
public MailBean getMailBean() {
return mailBean;
}
public void setMailBean(MailBean mailBean) {
this.mailBean = mailBean;
}
@Override
public void run() {
MailUtil.send(mailBean);
}
}
MailUtil,邮件发送工具类,将邮件发送类注入静态方法
package demo.mail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Service
public class MailUtil {
private static final Logger logger = LoggerFactory.getLogger(MailUtil.class);
//线程池核心线程数
private static final int COREPOOLSIZE = 1;
//线程池最大线程数
private static final int MAXMUMPOOLSIZE = 10;
//超过核心线程数,空闲线程等待任务的最长时间 单位 毫秒,0 的意思是 空闲线程直接销毁
private static final long KEEPALIVETIME = 0;
//当线程池中线程数等于核心线程数时,新创建的线程任务放到阻塞队列中去
private static final BlockingQueue<Runnable> EMAIL_QUEUE = new LinkedBlockingDeque<>(10);
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(COREPOOLSIZE, MAXMUMPOOLSIZE, KEEPALIVETIME,
TimeUnit.SECONDS, EMAIL_QUEUE, new ThreadPoolExecutor.AbortPolicy());
public static void send(MailBean mailBean) {
try {
MailSend.send(mailBean.getRecipients(), mailBean.getSubject(), mailBean.getContent());
} catch (Exception e) {
logger.error("mailutil error : ", e);
}finally {
logger.info("邮件发送 成功了!");
}
}
}
.properties,配置文件
#smtp服务器
mail.smtp.host=smtp.163.com
#smtp服务器的端口
mail.smtp.port=25
#如果为true,STARTTLS则在发出任何登录命令之前,启用使用命令(如果服务器支持)将连接切换到TLS保护的连接。请注意,必须配置适当的信任存储,以便客户端信任服务器的证书。默认为false。
mail.smtp.starttls.enable=true
#如果为true,则尝试使用AUTH命令认证用户。默认为false。
mail.smtp.auth=true
#指定使用指定套接字工厂时要连接的端口。如果未设置,将使用默认端口。
mail.smtp.socketFactory.port=25
#如果设置为true,则无法使用指定的套接字工厂类创建套接字将导致使用java.net.Socket该类创建套接字 。默认为true。
mail.smtp.socketFactory.fallback=false
#Tranport对象才会向SMTP服务器提交用户认证信息
mail.transport.protocol=smtp
mail.from=xxx@163.com
#ssl被smtp认证
mail.smtp.ssl.trust=smtp.163.com
#邮箱用户名
mail.username=xxx@163.com
#邮箱密码
mail.password=password
单元测试,要将邮件服务器,和验证发件人和密码改成对应的
package demo.mail;
import demo.DemoApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import java.util.ArrayList;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@SpringBootTest(classes = DemoApplication.class, webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public class MailUtilTest {
@Autowired
private MailUtil mailUtil;
@Test
public void send() throws Exception {
MailBean mailBean = new MailBean();
List<String> internetAddresses = new ArrayList<>();
internetAddresses.add("xiaomingtongxie@163.com");
MailContent mailContent = new MailContent();
mailContent.setContent("邮件内容为:23333333");
mailBean.setSubject("测试邮件发送");
mailBean.setRecipients(internetAddresses);
mailBean.setContent(mailContent);
mailUtil.send(mailBean);
}
}
感谢您的阅读,如果觉得对您有用,记得点赞哦。
先附上源码地址,博客有时间再更新
https://github.com/xiaomingtongxie/springboot-study.git
码云地址:
https://gitee.com/xiaomingnevermind/springboot-study.git