当前位置: 首页 > news >正文

SpringBoot整合Java Mail实现发送邮件

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>

发送结果
在这里插入图片描述

设计邮件记录日志

这里就不给出具体的代码了,表结构如下。
在这里插入图片描述
重试逻辑目前没有写,大家可以考虑加上重试逻辑。同时这个表也没有记录发送的邮件是和哪个业务关联的,也可以考虑记录。

总结

这里的记录发送日志,只能知道是否发送成功;接收方有没有接收到邮件是不能确定的,当然大部分情况下接收方都是可以收到。

参考

  1. 什么是授权码,它又是如何设置?
  2. 什么是 POP3/IMAP/SMTP 服务

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Study--Oracle-07-ASM自动存储管理(一)
  • GLM3源码学习
  • 《斯科特·凯尔比的风光摄影手册》读书笔记
  • 刷题之单词规律同构字符串(leetcode)
  • 2022-10-26 Qt6.5版本后视频渲染
  • Go 初始化一个字典value是列表
  • 前端/python脚本/转换-使用天地图下载的geojson(echarts4+如果直接使用会导致坐标和其他信息不全)
  • MongoDB - 查询操作符:比较查询、逻辑查询、元素查询、数组查询
  • 安全防御----防火墙综合实验2
  • 图论---匈牙利算法求二分图最大匹配的实现
  • pdf只要前几页,pdf中只要前几页怎么处理
  • pytorch-pytorch之LSTM
  • DockerCompose介绍,安装,使用
  • 【错题集-编程题】四个选项(DFS + 剪枝 + 哈希表)
  • 利用 AI 解放双手:把“贾维斯”带进现实 | 开源专题 No.64
  • [ JavaScript ] 数据结构与算法 —— 链表
  • 【React系列】如何构建React应用程序
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • 3.7、@ResponseBody 和 @RestController
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • LeetCode算法系列_0891_子序列宽度之和
  • Spark RDD学习: aggregate函数
  • Spring Cloud中负载均衡器概览
  • Vue2 SSR 的优化之旅
  • zookeeper系列(七)实战分布式命名服务
  • 工作中总结前端开发流程--vue项目
  • 将回调地狱按在地上摩擦的Promise
  • 罗辑思维在全链路压测方面的实践和工作笔记
  • 前端面试之闭包
  • 使用API自动生成工具优化前端工作流
  • 微服务核心架构梳理
  • 智能网联汽车信息安全
  • ​​​【收录 Hello 算法】9.4 小结
  • ‌‌雅诗兰黛、‌‌兰蔻等美妆大品牌的营销策略是什么?
  • # 达梦数据库知识点
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • (蓝桥杯每日一题)love
  • (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境
  • (一)Thymeleaf用法——Thymeleaf简介
  • (原)本想说脏话,奈何已放下
  • (中等) HDU 4370 0 or 1,建模+Dijkstra。
  • (转)GCC在C语言中内嵌汇编 asm __volatile__
  • (转)scrum常见工具列表
  • **登录+JWT+异常处理+拦截器+ThreadLocal-开发思想与代码实现**
  • *算法训练(leetcode)第三十九天 | 115. 不同的子序列、583. 两个字符串的删除操作、72. 编辑距离
  • .NET 8.0 发布到 IIS
  • .net 发送邮件
  • .NET/C# 中你可以在代码中写多个 Main 函数,然后按需要随时切换
  • .NET开发人员必知的八个网站
  • @Autowired多个相同类型bean装配问题
  • [2016.7.test1] T2 偷天换日 [codevs 1163 访问艺术馆(类似)]
  • [acwing周赛复盘] 第 94 场周赛20230311
  • [AIGC codze] Kafka 的 rebalance 机制
  • [AIGC] 深入浅出 Python中的`enumerate`函数
  • [Android] 240204批量生成联系人,短信,通话记录的APK