文章目录
实际开发时需要实现邮件发送,本文章实现如何从零实现邮件发送。也就是 Spring Boot 项目中如何实现邮箱发送。
Java发送邮箱的方式
1、前提:需要获取发件人邮箱的授权码,也就是打开POP3/IMAP/SMTP服务设置,拿到授权码。
2、获取到邮件服务器的 smtp 地址:
| 服务商 | smtp服务地址 | smtp服务端口 | pop3服务地址 | pop3服务端口 |
|---|---|---|---|---|
| 新浪: sina.com | smtp.sina.com.cn | 25 | pop3.sina.com.cn | 110 |
| 搜狐:sohu.com | smtp.sohu.com | 25 | pop3.sohu.com | 110 |
| 163:163.com | smtp.163.com | 25 | smtp.163.com | 110 |
| QQ:qq.com | smtp.qq.com | 25 或 465 或 587 | smtp.qq.com | 110 |
| foxmail:foxmail.com | smtp.foxmail.com | 25 | pop3.foxmail.com | 110 |
| QQ企业邮箱:exmail.qq.com | smtp.exmail.qq.com | 995 | pop3.exmail.qq.com | 587/465 |
1. 基于 Javax.mail 实现
先引入依赖:
xml
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
大致的流程:
1、创建配置项变量 Properties 对象,用于声明 smtp 相关配置;
2、创建一个Session,重写一个Authenticator,用于声明发件人邮箱地址和授权码;
3、利用 session 创建一个 MimeMessage 对象,再利用 MimeMessage 创建一个 MimeMessageHelper 对象,该对象用于设置收件人、发件人、抄送、秘密抄送、主题、内容、附件、发送时间等属性;
4、利用 Transport.send 方法发送邮件。
代码示例:
java
@Slf4j
public class EmailJavax {
// 也可以从配置文件中取值
// smtp服务地址
private static final String senderSmtpHost = "smtp.qq.com";
// 邮箱端口号
private static final String senderSmtpPort = "465";
// 发信人邮箱
private static final String senderEmail = "xxx@qq.com";
// 发信人邮箱授权码
private static final String senderPassword = "xxx";
/**
* 邮件发送
*
* @param subject 邮件主题
* @param content 邮件内容
* @param contentIsHtml 内容是否为html格式
* @param fromMailPersonalName 发件人昵称
* @param toMail 收件人邮箱
* @param ccMail 抄送人邮箱
* @param bccMail 秘密抄送人邮箱
* @param fileNames 文件名(本地路径)
*/
public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName, String toMail, String ccMail, String bccMail, List<String> fileNames) throws GeneralSecurityException, UnsupportedEncodingException, MessagingException {
// 1.创建配置项变量,用于声明 smtp 相关配置
Properties properties = System.getProperties();
// smtp服务地址
properties.put("mail.smtp.host", senderSmtpHost);
// smtp服务端口
properties.put("mail.smtp.port", senderSmtpPort);
// 开启验证
properties.put("mail.smtp.auth", "true");
// 开启TLS加密
properties.put("mail.smtp.starttls.enable", "true");
// 是否启用socketFactory,默认为true
properties.put("mail.smtp.socketFactory.fallback", "true");
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
properties.put("mail.smtp.ssl.enable", "true");
properties.put("mail.smtp.ssl.socketFactory", sf);
// 2.重写Authenticator,用于声明发件人邮箱地址和授权码
// 建立会话,将邮箱授权码给jvm
Session session = Session.getDefaultInstance(properties, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(senderEmail, senderPassword);
}
});
// 设置为true可以在控制台打印发送过程,生产环境关闭
session.setDebug(true);
// 3.创建MimeMessage对象
// 创建邮件对象
MimeMessage message = new MimeMessage(session);
// 创建MimeMessageHelper对象,通过MimeMessageHelper设置正文和附件,否则会导致两者显示不全
MimeMessageHelper helper = new MimeMessageHelper(message, true, "utf-8");
//设置发件人
helper.setFrom(new InternetAddress(senderEmail, fromMailPersonalName));
// 设置收件人,to为收件人,cc为抄送,bcc为密送
if (StringUtils.isEmpty(toMail)) {
log.error("邮件收件人为空");
return;
}
helper.setTo(InternetAddress.parse(toMail, false));
if (!StringUtils.isEmpty(ccMail)) {
helper.setCc(InternetAddress.parse(ccMail, false));
}
if (!StringUtils.isEmpty(bccMail)) {
helper.setBcc(InternetAddress.parse(bccMail, false));
}
// 设置邮件主题
helper.setSubject(subject);
//设置邮件正文内容
helper.setText(content, contentIsHtml);
//设置发送的日期
helper.setSentDate(new Date());
// 设置附件(注意这里的fileName必须是服务器本地文件名,不能是远程文件链接)
if (!CollectionUtils.isEmpty(fileNames)) {
for (String fileName : fileNames) {
FileDataSource fileDataSource = new FileDataSource(fileName);
helper.addAttachment(fileDataSource.getName(), fileDataSource);
}
}
// 4.调用Transport的send方法去发送邮件
Transport.send(message);
}
}
java
// 测试:
public class Test(){
public static void main(String[] args) throws MessagingException, GeneralSecurityException, UnsupportedEncodingException {
// excel表格的存放位置:
String fileName = "/xx/xx/xx/供应商接口参数.xlsx";
String html = "<h1>统计数据如下所示:</h1>" +
"<table border=\"1\">\n" +
" <tr>\n" +
" <th>月度销售额</th>\n" +
" <th>年度销售额</th>\n" +
" </tr>\n" +
" <tr>\n" +
" <td>10000</td>\n" +
" <td>2000000</td>\n" +
" </tr>\n" +
"</table>";
// 调方法:
EmailJavax.sendEmail("统计数据", html, true, "发送人名字", "收件人邮箱", null, null, Collections.singletonList(fileName));
}
}
关于附件上传的方法
附件上传有多种方式,除了上面用到的 FileDataSource 形式添加附件外,还有 文件、输入流的方式添加:
addAttachment(String attachmentFilename, DataSource dataSource)addAttachment(String attachmentFilename, File file)addAttachment(String attachmentFilename, InputStreamSource inputStreamSource)addAttachment(String attachmentFilename, InputStreamSource inputStreamSource, String contentType)
2. 基于 org.apache.commons.mail 实现
commons 包中提供了 Email 抽象类,该类下实现了
HtmlEmail(用于HTML正文,附件邮件发送)ImageHtmlEmail(用于HTML图片正文,附件邮件发送)MultiPartEmail(用于附件邮件发送)SimpleEmail(用于简单邮件发送)
其继承关系如图所示:

1、引入依赖:
xml
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.5</version>
</dependency>
2、实现:
java
@Slf4j
public class EmailCommons {
// 也可以从配置文件中取值
// smtp服务地址
private static final String senderSmtpHost = "smtp.qq.com";
// 邮箱端口号
private static final String senderSmtpPort = "465";
// 发信人邮箱
private static final String senderEmail = "xxx@qq.com";
// 发信人邮箱授权码
private static final String senderPassword = "xxx";
/**
* 邮件发送
*
* @param subject 邮件主题
* @param content 邮件内容
* @param contentIsHtml 内容是否为html格式
* @param fromMailPersonalName 发件人昵称
* @param toMail 收件人邮箱
* @param ccMail 抄送人邮箱
* @param bccMail 秘密抄送人邮箱
* @param fileList 附件
*/
public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName, String toMail, String ccMail, String bccMail, File[] fileList) throws GeneralSecurityException, UnsupportedEncodingException, MessagingException {
// 1.创建HtmlEmail对象
HtmlEmail email = new HtmlEmail();
// smtp服务地址
email.setHostName(senderSmtpHost);
// smtp服务端口
email.setSmtpPort("mail.smtp.port", senderSmtpPort);
email.setCharset("utf-8");
// 邮件验证
email.setAuthentication(senderEmail,senderPassword);
//设置发件人
email.setFrom(senderEmail, fromMailPersonalName);
// 设置收件人,to为收件人,cc为抄送,bcc为密送
if (StringUtils.isEmpty(toMail)) {
log.error("邮件收件人为空");
return;
}
email.addTo(toMail);
if (!StringUtils.isEmpty(ccMail)) {
email.addCc(ccMail);
}
if (!StringUtils.isEmpty(bccMail)) {
email.addBcc(bccMail);
}
// 设置邮件主题
email.setSubject(subject);
//设置邮件正文内容
if(contentIsHtml){
email.setHtmlMsg(content);
}else{
email.setMsg(content);
}
// 设置附件
if(!ObjectUtils.isEmpty(fileList)){
for (File file : fileList) {
EmailAttachment emailAttachment = new EmailAttachment();
emailAttachment.setName(MimeUtility.encodeText(file.getName()));
emailAttachment.setPath(file.getPath());
email.attach(emailAttachment);
}
}
// 4.调用send方法去发送邮件
email.send();
}
}
3、测试:
java
public class Test(){
public static void main(String[] args) throws MessagingException, GeneralSecurityException, UnsupportedEncodingException {
// excel表格的存放位置:
String fileName = "/xx/xx/xx/供应商接口参数.xlsx";
File file = new File(fileName);
String html = "<h1>统计数据如下所示:</h1>" +
"<table border=\"1\">\n" +
" <tr>\n" +
" <th>月度销售额</th>\n" +
" <th>年度销售额</th>\n" +
" </tr>\n" +
" <tr>\n" +
" <td>10000</td>\n" +
" <td>2000000</td>\n" +
" </tr>\n" +
"</table>";
EmailCommons.sendEmail("统计数据", html, true, "发送人名字", "收件人邮箱", null, null,new File[]{file} );
}
}
常见报错
1、535 Login Fail. Please enter your authorization code to login
原因:邮箱验证设置的账号密码错误
解决:注意参数值正确性:email.setAuthentication(发件人邮箱地址,邮箱授权码);
2、MessagingException: Got bad greeting from SMTP host: smtp.qq.com, port: 465, response: [EOF]
解决:commons.mail 发送邮件时,QQ 邮箱使用默认端口 25 即可
3. 基于 spring-boot-starter-mail 实现(推荐)
1、引入依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
2、使用配置文件:
yml
spring:
# 配置发送邮件的配置信息
mail:
# 配置smtp服务主机地址
host: smtp.qq.com
# 发送者邮箱
username: XXX@qq.com
# 配置密码,注意不是真正的密码,而是申请到的授权码
password: jlpXXXXXdecj
# 端口号:465或587
port: 465
# 默认的邮件编码为UTF-8
default-encoding: UTF-8
# 其他参数
properties:
mail:
# 配置SSL 加密工厂
smtp:
ssl:
# 本地测试,先放开ssl
enable: true
required: true
# 开启debug模式,这样邮件发送过程的日志会在控制台打印出来,方便排查错误
debug: true
3、实现:
java
/**
* 发送邮件类
*/
public class SendEmailUtil {
// 注入系统相关类
@Autowired
private JavaMailSender javaMailSender;
@Autowired
private MailProperties mailProperties;
// 发送者邮箱
// @Value("${spring.mail.username}")
// private String sendMailer;
/**
* 邮件发送1
*
* @param subject 邮件主题
* @param content 邮件内容
* @param contentIsHtml 内容是否为html格式
* @param fromMailPersonalName 发件人昵称
* @param toMail 收件人邮箱
* @param ccMail 抄送人邮箱
* @param bccMail 秘密抄送人邮箱
* @param fileNames 文件名(本地文件名)
*/
public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName,
String toMail, String ccMail, String bccMail, List<String> fileNames) throws MessagingException, UnsupportedEncodingException {
// true 代表支持复杂的类型
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
/* 邮件发信人:两种写法:
1. 定义成员变量获取application.yml的username属性
@Value("${spring.mail.username}")
private String sendMailer;
helper.setFrom(sendMailer,发件人名称)
2. 注入系统类的对象,然后调方法获取,获取的值也是application.yml文件中的值
@Autowired
private MailProperties mailProperties;
helper.setFrom(mailProperties.getUsername(),发件人名称);
*/
helper.setFrom(mailProperties.getUsername(), fromMailPersonalName);
// 邮件收信人 1或多个
helper.setTo(toMail);
if (!ObjectUtils.isEmpty(ccMail)) {
// 邮件抄送人
helper.setCc(ccMail);
}
if (!ObjectUtils.isEmpty(bccMail)) {
// 邮件私密抄送人
helper.setBcc(bccMail);
}
// 邮件主题
helper.setSubject(subject);
// 邮件内容 contentIsHtml值为 true 代表支持html
helper.setText(content, contentIsHtml);
// 设置附件(注意这里的fileName必须是服务器本地文件名,不能是远程文件链接)
if (!CollectionUtils.isEmpty(fileNames)) {
for (String fileName : fileNames) {
// 添加邮件附件
FileDataSource fileDataSource = new FileDataSource(fileName);
helper.addAttachment(fileDataSource.getName(), fileDataSource);
}
}
// 发送邮件
javaMailSender.send(mimeMessage);
}
/**
* 邮件发送2 -- 方法优化 -- 文件对象
*
* @param subject 邮件主题
* @param content 邮件内容
* @param contentIsHtml 内容是否为html格式
* @param fromMailPersonalName 发件人昵称
* @param toMail 收件人邮箱
* @param ccMail 抄送人邮箱
* @param bccMail 秘密抄送人邮箱
* @param files 文件对象
*/
public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName,
String toMail, String ccMail, String bccMail, File[] files) throws MessagingException, UnsupportedEncodingException {
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(mailProperties.getUsername(), fromMailPersonalName);
helper.setTo(toMail);
if (!ObjectUtils.isEmpty(ccMail)) {
helper.setCc(ccMail);
}
if (!ObjectUtils.isEmpty(bccMail)) {
helper.setBcc(bccMail);
}
helper.setSubject(subject);
helper.setText(content, contentIsHtml);
// 设置附件,不能是远程文件
if (!ObjectUtils.isEmpty(files)) {
for (File file : files) {
helper.addAttachment(file.getName(), file);
}
}
javaMailSender.send(message);
}
/**
* 邮件发送3 -- 方法优化 -- 使用流
*
* @param subject 邮件主题
* @param content 邮件内容
* @param contentIsHtml 内容是否为html格式
* @param fromMailPersonalName 发件人昵称
* @param toMail 收件人邮箱
* @param ccMail 抄送人邮箱
* @param bccMail 秘密抄送人邮箱
* @param fileName 文件名称
* @param fileInput 文件流
*/
public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName,
String toMail, String ccMail, String bccMail, String fileName, InputStreamSource fileInput) throws MessagingException, UnsupportedEncodingException {
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(mailProperties.getUsername(), fromMailPersonalName);
helper.setTo(toMail);
if (!ObjectUtils.isEmpty(ccMail)) {
helper.setCc(ccMail);
}
if (!ObjectUtils.isEmpty(bccMail)) {
helper.setBcc(bccMail);
}
helper.setSubject(subject);
helper.setText(content, contentIsHtml);
// 设置附件,不能是远程文件
if (fileInput != null) {
helper.addAttachment(fileName, fileInput);
}
javaMailSender.send(message);
}
}
关于邮件发送的方法参数: 上面几个方法,最后接收附件的参数都不一样,说明可以灵活变化
sendEmail(xxx, List<String> fileNames):可以接收多个附件,其中传的时候,就是附件的绝对路径sendEmail(xxx, File[] files):可以接收多个附件,传的时候,就是附件的文件对象sendEmail(xxx, InputStreamSource fileInput):接收一个附件,传的时候,就是附件的流
5、测试:
java
/**
* excel表格生成工具
*/
public class ExcelUtil {
/**
* 生成excel文件
*
* @param fileName excel文件路径
* @param dataList 数据列表
* @param clazz 导出对象类
* @param <T>
* @return
*/
public static <T> File generateExcel(String fileName, List<T> dataList, Class<T> clazz) {
// 生成文件
File file = new File(fileName);
// 单sheet写入
EasyExcel.write(file, clazz).sheet("XXX").doWrite(dataList);
return file;
}
/**
* 生成excel文件 -- 方法优化 -- 用流
*
* @param dataList 数据列表
* @param clazz 导出对象类
* @param <T>
* @return
*/
public static <T> ByteArrayOutputStream generateExcel(List<T> dataList, Class<T> clazz) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
// 单excel写入
EasyExcel.write(out, clazz).sheet("XXX").doWrite(dataList);
return out;
}
}
java
public class Test(){
public static void main(String[] args) throws MessagingException, GeneralSecurityException, UnsupportedEncodingException {
String content = "客户统计数据如附件所示";
// 测试邮件发送1
// excel表格的存放位置:
String fileName = "/xx/xx/xx/供应商接口参数.xlsx";
String html = "<h1>统计数据如下所示:</h1>" +
"<table border=\"1\">\n" +
" <tr>\n" +
" <th>月度销售额</th>\n" +
" <th>年度销售额</th>\n" +
" </tr>\n" +
" <tr>\n" +
" <td>10000</td>\n" +
" <td>2000000</td>\n" +
" </tr>\n" +
"</table>";
SendEmailUtil.sendEmail("统计数据", html, true, "发送人名字", "收件人邮箱", null, null, Arrays.asList(fileName));
// 测试邮件发送2
File excel = ExcelUtil.generateExcel("文件名", 表格映射的实体类对象, 表格映射的实体类.class);
SendEmailUtil.sendEmail("统计数据", content, false, "发送人名字", "收件人邮箱", null, null, new File[]{excel});
// 测试邮件发送3
ByteArrayOutputStream bos = ExcelUtil.generateExcel(userInfos, UserInfo.class);
SendEmailUtil.sendEmail("统计数据", content, false, "发送人名字", "收件人邮箱", null, null, fileName, new ByteArrayResource(bos.toByteArray()));
}
}
注意: 实现 excel 生成,然后发送邮箱 的代码,可以查看这篇文章:生成 excel 并发送邮箱
至此!文章的内容结束!!记得关注收藏,有更多精彩内容!!!