SpringBoot整合Java Mail实现发送邮件
实现
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
发送邮件配置
这里使用qq邮箱发送邮件,需要开启qq邮箱的smtp服务,同时需要拿到授权码。
如果不知道怎么开启服务和获取授权码,可以点击文章末尾的参考文章了解。
spring:
application:
name: send-mail
mail:
host: smtp.qq.com
port: 587
protocol: smtp
username: xxxxx@qq.com
password: ybfbprpciavceaig #password就是授权码
default-encoding: UTF-8
test-connection: true
properties:
smtp:
auth: true
starttls:
enable: true
邮件发送事件
在需要发送邮件的地方,发布这个事件即可。
public class SendEmailEvent extends ApplicationEvent {
private String subject;
private List<String> to;
private String content;
private List<File> files;
private String from;
public SendEmailEvent(Object source, String subject, List<String> to, String content, List<File> files, String from) {
super(source);
this.to =to;
this.content = content;
this.files = files;
this.subject = subject;
this.from = from;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public List<String> getTo() {
return to;
}
public void setTo(List<String> to) {
this.to = to;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public List<File> getFiles() {
return files;
}
public void setFiles(List<File> files) {
this.files = files;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
}
邮件发送事件监听器
循环发送邮件,支持发送附件;使用@Async注解支持异步发送,即使用单独的线程发送邮件
@Component
@EnableAsync
public class SendEmailEventListener implements ApplicationListener<SendEmailEvent> {
@Autowired
private JavaMailSender mailSender;
private Logger logger = LoggerFactory.getLogger(SendEmailEventListener.class);
@Async
@Override
public void onApplicationEvent(SendEmailEvent event) {
//发送邮件
String content = event.getContent();
String subject = event.getSubject();
List<String> to = event.getTo();
List<File> files = event.getFiles();
String from = event.getFrom();
MimeMessage mimeMessage = mailSender.createMimeMessage();
try {
for (String toEmail: to) {
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
//主题
helper.setSubject(subject);
//发件人
helper.setFrom(from);
//收件人
helper.setTo(toEmail);
//内容
helper.setText(emailContent);
//附件
for (File file : files) {
helper.addAttachment(file.getName(), new FileDataSource(file));
}
mailSender.send(mimeMessage);
}
} catch (Exception e) {
logger.error("发送邮件失败" + e.getMessage() + " " + e.getCause());
}
}
}
发送邮件线程池配置
@Configuration
public class MailConfig {
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(5);
executor.initialize();
return executor;
}
}
业务调用
@GetMapping("/send-mail1")
public String sendMail1() {
ArrayList<String> emails = new ArrayList<>();
emails.add("xxxx@163.com");
String from = "xxxxxxxx@qq.com";
applicationContext.publishEvent(new SendEmailEvent(
this, "测试邮件发送", emails, "测试发送邮件", new ArrayList<>(), from));
return "sendMail1";
}
发送结果
集成freemarker,自定义邮件模版发送邮件
引入freemarker的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
邮件模版配置
spring:
freemarker:
template-loader-path: classpath:/templates/
suffix: .ftl
charset: UTF-8
content-type: text/html;charset=utf-8
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
url: jdbc:mysql://localhost:3306/foodie_dev?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
freemarker配置类
@Configuration
public class FtlConfiguration {
@Bean
public FreeMarkerConfigurer getFreeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath("classpath:/templates/");
return configurer;
}
}
发送代码改造
这里模版中的数据是写死的,可以改造SendEmailEvent传过来
@Component
@EnableAsync
public class SendEmailEventListener implements ApplicationListener<SendEmailEvent> {
@Autowired
private JavaMailSender mailSender;
@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer;
private Logger logger = LoggerFactory.getLogger(SendEmailEventListener.class);
@Async
@Override
public void onApplicationEvent(SendEmailEvent event) {
//发送邮件
String content = event.getContent();
String subject = event.getSubject();
List<String> to = event.getTo();
List<File> files = event.getFiles();
String from = event.getFrom();
MimeMessage mimeMessage = mailSender.createMimeMessage();
String emailContent = "";
try {
for (String toEmail: to) {
// 加载模板
Configuration configuration = freeMarkerConfigurer.getConfiguration();
Template email = configuration.getTemplate("email.ftl");
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("title", "Welcome to FreeMarker");
dataModel.put("message", "Hello, world!");
emailContent = FreeMarkerTemplateUtils.processTemplateIntoString(email, dataModel);
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
//主题
helper.setSubject(subject);
//发件人
helper.setFrom(from);
//收件人
helper.setTo(toEmail);
//内容,如果使用了ftl则第二个参数设置为true,否则邮件中会是html字符串
helper.setText(emailContent, true);
//附件
for (File file : files) {
helper.addAttachment(file.getName(), new FileDataSource(file));
}
mailSender.send(mimeMessage);
}
} catch (Exception e) {
logger.error("发送邮件失败" + e.getMessage() + " " + e.getCause());
}
}
}
模版如下
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1>${title}</h1>
<h1>Today is good day!</h1>
<p>${message}</p>
</body>
</html>
发送结果
设计邮件记录日志
这里就不给出具体的代码了,表结构如下。
重试逻辑目前没有写,大家可以考虑加上重试逻辑。同时这个表也没有记录发送的邮件是和哪个业务关联的,也可以考虑记录。
总结
这里的记录发送日志,只能知道是否发送成功;接收方有没有接收到邮件是不能确定的,当然大部分情况下接收方都是可以收到。
参考
- 什么是授权码,它又是如何设置?
- 什么是 POP3/IMAP/SMTP 服务