0. 引言

邮件发送是我们日常开发中比较常见的功能,常用于预警信息提醒、统计数据定期发送等需求。一般该方法会由前人封装好,实际开发时只需要调用即可,但具体怎么实现的,如何从零实现邮件发送,这是我们要掌握的。

上一次我们讲解了基于javax.mail实现邮件发送,今天我们接着讲解基于​​org.apache.commons.mail​​的实现方式

  • ​​基于javax.mail实现​​

1. 环境准备

1.1 开发环境

以下演示均基于各组件当前最新的稳定版本实现,jdk基于1.8版本

commons-email 1.5

1.2 开启邮箱协议与授权

其次我们需要了解的是,程序要发送邮件,是需要一个邮箱账号的, 并且其账号需要开启SMTP邮件协议以及邮件授权码,并不是密码。

以下我们以QQ邮箱为例,示范其开启过程,其他邮箱大同小异。

1、登陆邮箱,点击​​设置​​​,进入​​账户​​,下拉页面

springboot:java实现邮件及附件发送、HTML正文的三种方式(二)【附带源码】_Email

2、找到​​POP3/IMAP/SMTP​​​服务设置。这里我们可以开启​​POP3/SMTP​​​或者​​IMAP/SMTP​​服务,两者的区别

springboot:java实现邮件及附件发送、HTML正文的三种方式(二)【附带源码】_邮件发送_02

3、点击​​开启​​后,会要求你发送短信验证

springboot:java实现邮件及附件发送、HTML正文的三种方式(二)【附带源码】_java_03

4、发送后,点击​​我已发送​​,然后会给你一个授权码,将该码保存下来,这就是我们需要的授权码。

springboot:java实现邮件及附件发送、HTML正文的三种方式(二)【附带源码】_Email_04

5、其次我们需要获取到邮件服务器的smtp地址,比如我们这里用的是qq邮箱,其地址就是​​smtp.qq.com​​。对应类型邮箱的smtp地址直接百度即可。

1.3 常见的邮箱服务及端口

服务商

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

pop3.163.com

110

QQ qq.com

smtp.qq.com

25

pop3.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

2. 实现

2.1 org.apache.commons.mail实现

2.1.1 思路

1、​​commons​​​包中提供了​​Email​​​抽象类,该类下实现了​​HtmlEmail​​​,​​ImageHtmlEmail​​​,​​MultiPartEmail​​​,​​SimpleEmail​

springboot:java实现邮件及附件发送、HTML正文的三种方式(二)【附带源码】_spring boot_05

其继承关系如图所示:

springboot:java实现邮件及附件发送、HTML正文的三种方式(二)【附带源码】_Email_06

  • ​SimpleEmail​​用于简单邮件发送
  • ​MultiPartEmail​​ 用于附件邮件发送
  • ​HtmlEmail​​ 用于HTML正文,附件邮件发送
  • ​ImageHtmlEmail​​ 用于HTML图片正文,附件邮件发送

2、这里因为我们要实现HTML正文以及附件发送,因此我们创建​​HtmlEmail​​对象,且设置各种参数属性。

3、调用​​email.send()​​方法发送邮件

2.1.2 实操

1、引入依赖

<!--        邮件依赖 -->        
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.5</version>
</dependency>

<!-- @ConfigurationProperties依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

2、我们将配置项提取到配置文件​​application.yml​​中

email:
smtp:
host: smtp.qq.com
email: xxx@qq.com
name: 邮件提醒系统
password: xxx
port: 25

3、创建配置类,关联配置项

@Data
@Component
@ConfigurationProperties(value = "email.smtp")
public class SmtpProperties {

/**
* smtp服务地址
*/
private String host;

/**
* 发件人邮箱
*/
private String email;

/**
* 发件人昵称
*/
private String name;

/**
* 邮箱授权码
*/
private String password;

/**
* 邮箱服务端口
*/
private Integer port=25;
}

4、创建工具类,实现发送功能

/**
* @author benjamin_5
* @Description
* @date 2022/10/3
*/
@AllArgsConstructor
@Component
public class EmailCommonsUtil {
private static final Log logger = LogFactory.getLog(EmailCommonsUtil.class);

private final SmtpProperties emailProperties;

/**
* 邮件发送
* @param subject 邮件主题
* @param content 邮件内容
* @param contentIsHtml 内容是否为html格式
* @param toMail 收件人邮箱
* @param ccMail 抄送人邮箱
* @param bccMail 秘密抄送人邮箱
* @param fileList 附件
*/
public void sendEmail(String subject, String content,boolean contentIsHtml,
String[] toMail, String[] ccMail, String[] bccMail, File[] fileList)
throws EmailException, UnsupportedEncodingException {
HtmlEmail email = new HtmlEmail();
// smtp服务地址
email.setHostName(emailProperties.getHost());
// 邮件验证
email.setAuthentication(emailProperties.getEmail(),emailProperties.getPassword());
// smtp端口
email.setSmtpPort(emailProperties.getPort());
email.setCharset("utf-8");
// 发件人邮箱地址及昵称
email.setFrom(emailProperties.getEmail(),emailProperties.getName());
// 收件人邮箱
email.addTo(toMail);
if(!ObjectUtils.isEmpty(ccMail)){
// 抄送人邮箱
email.addCc(ccMail);
}
if(!ObjectUtils.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);
}
}
// 发送邮件
email.send();
logger.info("邮件发送完成");
}

}

5、调用测试,我们创建一个接口来模拟测试

@RestController
@AllArgsConstructor
public class EmailController {

private final EmailCommonsUtil emailCommonsUtil;

@GetMapping("sendCommonEmail")
public void sendCommonEmail(){
String subject = "这是一个测试标题";
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>";
String[] toMail = new String[]{"wuhanxue5@sina.com"};
String[] ccMail = new String[]{"wuhanxue5@163.com"};
File file = new File("/Users/wuhanxue/Downloads/canal mysql到es数据同步.png");
try {
emailCommonsUtil.sendEmail(subject,html,true,toMail,ccMail,null,new File[]{file});
} catch (EmailException | UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}

4、浏览器访问该接口​​http://localhost:8080/sendCommonEmail​

邮件接收成功,附件和HTML正文也显示正常

springboot:java实现邮件及附件发送、HTML正文的三种方式(二)【附带源码】_java_07

查看抄送邮箱,接收正常

springboot:java实现邮件及附件发送、HTML正文的三种方式(二)【附带源码】_邮件发送_08

2.1.4 常见报错

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即可

源码地址

以上演示的源码可以在如下地址中下载

​git源码地址​

关注专栏,了解后续内容

  • 基于spring-boot-starter-mail实现邮件发送