SpringBoot整合Java Mail实现发送邮件
实现
引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency>
发送邮件配置
这里使用qq邮箱发送邮件,需要开启qq邮箱的smtp服务,同时需要拿到授权码。
如果不知道怎么开启服务和获取授权码,可以点击文章末尾的参考文章了解。
spring:application:name: send-mailmail:host: smtp.qq.comport: 587protocol: smtpusername: xxxxx@qq.compassword: ybfbprpciavceaig #password就是授权码default-encoding: UTF-8test-connection: trueproperties:smtp:auth: truestarttls: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> {@Autowiredprivate JavaMailSender mailSender;private Logger logger = LoggerFactory.getLogger(SendEmailEventListener.class);@Async@Overridepublic 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 {@Beanpublic 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: .ftlcharset: UTF-8content-type: text/html;charset=utf-8datasource:driver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: rooturl: jdbc:mysql://localhost:3306/foodie_dev?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
freemarker配置类
@Configuration
public class FtlConfiguration {@Beanpublic FreeMarkerConfigurer getFreeMarkerConfigurer() {FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();configurer.setTemplateLoaderPath("classpath:/templates/");return configurer;}
}
发送代码改造
这里模版中的数据是写死的,可以改造SendEmailEvent传过来
@Component
@EnableAsync
public class SendEmailEventListener implements ApplicationListener<SendEmailEvent> {@Autowiredprivate JavaMailSender mailSender;@Autowiredprivate FreeMarkerConfigurer freeMarkerConfigurer;private Logger logger = LoggerFactory.getLogger(SendEmailEventListener.class);@Async@Overridepublic 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 服务