SpringBoot入门之五 整合邮件服务
1. 应用场景
邮件功能的应用场景可谓十分广泛,诸如注册用户、密码找回,业务推广、消息通知、以及一些程序异常通知等都需要使用到该功能。
正是由于邮件功能的使用广泛,因此springboot也加在它的组件中添加了邮件。
2.配置
2.1maven依赖
springboot中已经给我们准备好了邮件的相关组件,我们只要在springboot项目中将其添加即可。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
添加后继续查看这个组件的相关依赖,可见里面实际也是封装了javax.mail的邮件收发相关类。
[INFO] +- org.springframework.boot:spring-boot-starter-mail:jar:2.0.0.RELEASE:compile
[INFO] | +- org.springframework.boot:spring-boot-starter:jar:2.0.0.RELEASE:compile
[INFO] | | +- org.springframework.boot:spring-boot:jar:2.0.0.RELEASE:compile
[INFO] | | +- org.springframework.boot:spring-boot-autoconfigure:jar:2.0.0.RELEASE:compile
[INFO] | | +- org.springframework.boot:spring-boot-starter-logging:jar:2.0.0.RELEASE:compile
[INFO] | | | +- ch.qos.logback:logback-classic:jar:1.2.3:compile
[INFO] | | | | \- ch.qos.logback:logback-core:jar:1.2.3:compile
[INFO] | | | +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.10.0:compile
[INFO] | | | | \- org.apache.logging.log4j:log4j-api:jar:2.10.0:compile
[INFO] | | | \- org.slf4j:jul-to-slf4j:jar:1.7.25:compile
[INFO] | | +- javax.annotation:javax.annotation-api:jar:1.3.2:compile
[INFO] | | \- org.yaml:snakeyaml:jar:1.19:runtime
[INFO] | +- org.springframework:spring-context:jar:5.0.4.RELEASE:compile
[INFO] | | +- org.springframework:spring-aop:jar:5.0.4.RELEASE:compile
[INFO] | | +- org.springframework:spring-beans:jar:5.0.4.RELEASE:compile
[INFO] | | \- org.springframework:spring-expression:jar:5.0.4.RELEASE:compile
[INFO] | +- org.springframework:spring-context-support:jar:5.0.4.RELEASE:compile
[INFO] | \- com.sun.mail:javax.mail:jar:1.6.1:compile
[INFO] | \- javax.activation:activation:jar:1.1:compile
2.2 application.xml
#我这里使用QQ邮箱来发送邮件,因此配置的host是smtp.qq.com,使用其他邮箱需要找到对应的host
spring.mail.host=smtp.qq.com
#发送邮件的邮箱账号
spring.mail.username=*********@qq.com
#需要登录qq邮箱开启smtp服务 发送邮件的邮箱的SMTP服务密码(有的邮箱使用的是邮箱密码,不同邮箱可能不同)
spring.mail.password=**********
#是否进行身份验证
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
3.普 发送
我们首先编写一个简单text邮件的样例,之后会再在样例的demo上进行其他几种复杂邮件的发送,以及部分源码的解析。
3.1发送文本邮件
public void sendSimpleEmail() {
// 构造Email消息
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("XXX@qq.com");
message.setTo("****@qq.com");
//邮件主题
message.setSubject("hello");
//邮件内容
message.setText(" this is test!");
javaMailSender.send(message);
}
3.2发送带附件邮件
public void sendMimeEmail() throws MessagingException {
// MimeMessage 本身的 API 有些笨重,我们可以使用 MimeMessageHelper
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
// 第二个参数是 true ,表明这个消息是 multipart类型的/
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
mimeMessageHelper.setFrom("XXX@qq.com");
mimeMessageHelper.setTo("****@qq.com");
mimeMessageHelper.setSubject("附件邮件主题");
mimeMessageHelper.setText("附件邮件内容");
//添加附件,第一个参数表示添加到 Email 中附件的名称,第二个参数是图片资源
mimeMessageHelper.addAttachment("test.png", new ClassPathResource("public/images/boot.png"));
javaMailSender.send(mimeMessage);
}
3.3 发送html格式的文本邮件
public void htmlEmail() throws MessagingException {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
mimeMessageHelper.setFrom("XXX@qq.com");
mimeMessageHelper.setTo("XXX@qq.com");
mimeMessageHelper.setSubject("富文本邮件主题");
String html = "<html><body><h4>Hello, world</h4><img src='cid:boot' /></body></html>";
mimeMessageHelper.setText(html, true);
// 设置内嵌元素 cid,第一个参数表示内联图片的标识符,第二个参数标识资源引用
mimeMessageHelper.addInline("test", new ClassPathResource("public/images/boot.png"));
javaMailSender.send(mimeMessage);
}
3.4多个邮件接收人
我们可以以下面的两种形式来将邮件发送给多个接收者:
数组。
多个参数。
// 邮件接受者
mailMessage.sendMsg("","","");
mailMessage.sendMsg(new String[]{"",""});
3.5抄送
添加抄送者与添加接受者的方式差不多,区别在于方法名,添加抄送者方法为setCc():
同样也可以添加一个,或以数组和多参数形式添加多个抄送者:
// 邮件抄送者
mailMessage.setCc("");
mailMessage.setCc("","");
mailMessage.setCc(new String[]{"",""});
5.整合thymeleaf模板
5.1 自定义邮件内容实体,编写可重复使用的工具类
<!-- 引入lomhok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
@Data
public class MailEntity {
// 发件人
@Value("${spring.mail.username}")
private String mailFrom;
// 收件人
private String[] mailTo;
// 抄送
private String[] mailToCC;
// 邮件标题
private String subject;
// 邮件内容
private String context;
// 附件
private String[] attachFiles;
// 邮件模板变量
private HashMap<String, Object> variableMap;
public MailEntity() {}
public MailEntity(String subject, String context, String[] mailToCC, String[] mailTo) {
this.subject = subject;
this.context = context;
this.mailTo = mailTo;
this.mailToCC = mailToCC;
}
public MailEntity(String subject, String context, String[] mailToCC, String[] mailTo, String[] attachFiles) {
this.subject = subject;
this.context = context;
this.mailTo = mailTo;
this.mailToCC = mailToCC;
this.attachFiles = attachFiles;
}
public MimeMessage convertTo(MimeMessage message) throws MessagingException {
MimeMessageHelper messageHelper = new MimeMessageHelper(message, true);
messageHelper.setSubject(getSubject());
messageHelper.setFrom(mailFrom);
messageHelper.setTo(getMailTo());
// 这里后面的true,用来让context内容以html格式进行展示,如果不设置,里面的链接会被作为普通字符串展示
messageHelper.setText(getContext(), true);
// 添加附件
if (null != attachFiles) {
for (String filePath : attachFiles) {
FileSystemResource fileSystemResource = new FileSystemResource(new File(filePath));
String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
messageHelper.addAttachment(fileName, fileSystemResource);
}
}
return message;
}
public SimpleMailMessage convertTo() {
SimpleMailMessage mailMessage = new SimpleMailMessage();
// 邮件发送者,这里不能随便填写,必须是真实的发送邮件的邮箱名称
mailMessage.setFrom(mailFrom);
// 邮件接受者
mailMessage.setTo(getMailTo());
// 邮件主题
mailMessage.setSubject(getSubject());
// 邮件内容
mailMessage.setText(getContext());
if (!StringUtils.isEmpty(getMailToCC())) {
mailMessage.setCc(getMailToCC());
}
return mailMessage;
}
}
@Component
public class MailService {
@Autowired
private JavaMailSender mailSender;
public void sendMsg(MailEntity record) {
// 发送邮件
mailSender.send(record.convertTo());
}
}
5.2 pom.xml中引入依赖thymeleaf
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
5.3 MailService工具类中增加使用邮件模板的方法
@Component
public class MailService {
@Autowired
private JavaMailSender mailSender;
@Autowired
private TemplateEngine templateEngine;
public void sendMsgByThymeleafTemplate(MailEntity record) {
MimeMessage mimeMessage = null;
try {
// 添加正文(使用thymeleaf模板)
Context context = new Context();
context.setVariables(record.getVariableMap());
String content = this.templateEngine.process("email", context);
record.setContext(content);
mimeMessage = mailSender.createMimeMessage();
mimeMessage = record.convertTo(mimeMessage);
// 发送邮件
mailSender.send(mimeMessage);
} catch (MessagingException e) {
e.printStackTrace();
}
}
5.4 邮件模板
html的邮件模板路径放置在classpath:resources/templates/email.html
测试类
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Email</title>
</head>
<body>
<img src='cid:boot'>
<h4><span th:text="${subject}">hello </span> </h4>
<i><span th:text="${content}">Hello world!</span></i>
</body>
</html>
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootTeach5ApplicationTests {
@Autowired
private MailService mailService;
@Test
public void contextLoads() {
String[] mailTo = {"407737980@qq.com"};
String[] mailTo2 = {"407737980@qq.com", "407737980@qq.com"};
// 抄送
String[] mailToCC = {"407737980@qq.com"};
String[] attachFiles = {"C:\\Users\\indexvc\\Downloads\\微信截图_20200115221555.png"};
sendMsgByThymeleafTemplate
// 发送带简单html格式正文的邮件
mailService.sendHtmlMsg(new MailEntity("hello ", "<a href=\"#\">链接</a>", null, mailTo));
// 发送带附件的邮件
mailService.sendHtmlMsg(new MailEntity("hello ", "hello !This is a test! ", null, mailTo, attachFiles));
// 发送多个人收件人
mailService.sendMsg(new MailEntity("hello ", "hello !This is a test! ", mailToCC, mailTo2));
// 发送单个人收件人
mailService.sendMsg(new MailEntity("hello ", "hello !This is a test! ", null, mailTo));
// 抄送某人
mailService.sendMsg(new MailEntity("hello ", "hello !This is a test! ", mailToCC, mailTo));
}
}
运行测试类,发送结果如下
6. 整合Freemarker模板
6.1 引入pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
6.2 配置properties文件
#配置模板路径,默认是templates,可以不用配置
spring.freemarker.charset= UTF-8
spring.freemarker.allow-request-override= false
spring.freemarker.cache= false
spring.freemarker.expose-request-attributes= false
spring.freemarker.expose-session-attributes= false
spring.freemarker.content-type= text/html
spring.freemarker.template-loader-path= classpath:/templates/
spring.freemarker.expose-spring-macro-helpers= false
spring.freemarker.check-template-location= true
spring.freemarker.enabled= true
6.3 编写邮件模板html
html的邮件模板路径放置在classpath:resources/templates/email.ftl
6.4 整合freemark模板引擎的方法
@Autowired
private Configuration freeMarkerConfiguration;
public void sendMsgByFreemarkerTemplate(MailEntity record) {
record.setMailFrom(mailFrom);
MimeMessage mimeMessage = null;
try {
// 通过指定模板名获取FreeMarker模板实例
Template t = freeMarkerConfiguration.getTemplate("email.ftl", "utf-8");
// FreeMarker通过Map传递动态数据
// 注意动态数据的key和模板标签中指定的属性相匹配
// 解析模板并替换动态数据,最终code将替换模板文件中的${code}标签。
String mailText = FreeMarkerTemplateUtils.processTemplateIntoString(t, record.getVariableMap());
record.setContext(mailText);
mimeMessage = mailSender.createMimeMessage();
mimeMessage = record.convertTo(mimeMessage);
// 发送邮件
mailSender.send(mimeMessage);
} catch (Exception e) {
e.printStackTrace();
}
}
执行测试类,发送即可
源码地址
https://gitee.com/xiaolaifeng/sample.springboot/tree/master/springboot-teach5