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 服务

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/46058.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode3200. 三角形的最大高度

Every day a Leetcode 题目来源&#xff1a;3200. 三角形的最大高度 解法1&#xff1a;模拟 枚举第一行是红色还是蓝色&#xff0c;再按题意模拟即可。 代码&#xff1a; /** lc appleetcode.cn id3200 langcpp** [3200] 三角形的最大高度*/// lc codestart class Solutio…

java.sql.SQLException: Before start of result set

情况描述&#xff0c;在通过JDBC连接数据库时&#xff0c;想直接判断获取的值是否存在&#xff0c;运行时报错。 翻译&#xff1a; 在开始结果集之前 报错截图 解决问题的方法&#xff1a;对结果集ResultSet进行操作之前&#xff0c;一定要先用ResultSet.next()将指针移动至…

RAG 效果提升的最后一步—— 微调LLM

如果说&#xff0c;rerank能够让RAG的效果实现百尺竿头更进一步&#xff0c;那么LLM微调应该是RAG效果提升的最后一步。 把召回的数据&#xff0c;经过粗排&#xff0c;重排序后&#xff0c;送给模型&#xff0c;由模型最后总结答案。LLM的确已经是RAG的最后一步了。 这里还是会…

C#可空类型与数组

文章目录 可空类型NULL合并运算符&#xff08;??&#xff09;数组数组声明数组初始化数组赋值数组访问多维数组交错数组数组类数组类的常用属性数组类的常用方法 可空类型 C#提供了一种特殊的数据类型&#xff0c;nullable类型&#xff08;可空类型&#xff09;&#xff0c;可…

<数据集>夜间车辆识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;5000张 标注数量(xml文件个数)&#xff1a;5000 标注数量(txt文件个数)&#xff1a;5000 标注类别数&#xff1a;8 标注类别名称&#xff1a;[car, pedestrian, traffic light, traffic sign, bicycle, bus, truck…

vue学习day08-v-model详解、sync修饰符、ref和$refs获取dom组件、Vue异步更新和$nextTick

25、v-model详解 &#xff08;1&#xff09;v-model原理 1&#xff09;原理: v-model本质上是一个语法糖&#xff0c;比如&#xff1a;在应用于输入框时&#xff0c;就是value属性与input事件的合写。 2&#xff09;作用 ①数据变&#xff0c;视图变 ②视图变&#xff0c…

短链接服务Octopus-搭建实战

[WARNING] The POM for cn.throwx:octopus-contract:jar:1.0-SNAPSHOT is missing, no dependency information available 解决方案&#xff1a; cd octopus-contract/ mvn install -------------- ➜ octopus-server git:(master) ✗ mkdir -p /data/log-center/octopus/s…

DockerCompose介绍,安装,使用

DockerCompose 1、Compose介绍 将单机服务-通过Dockerfile 构建为镜像 -docker run 成为一个服务 user 8080 net 7000 pay 8181 admin 5000 监控 .... docker run 单机版、一个个容器启动和停止问题&#xff1a; 前面我们使用Docker的时候&#xff0c;定义 Dockerfil…

Lottery 分布式抽奖(个人向记录总结)

1.搭建&#xff08;DDDRPC&#xff09;架构 DDD——微服务架构&#xff08;微服务是对系统拆分的方式&#xff09; &#xff08;Domain-Driven Design 领域驱动设计&#xff09; DDD与MVC同属微服务架构 是由Eric Evans最先提出&#xff0c;目的是对软件所涉及到的领域进行建…

.NET MAUI开源架构_2.什么是 .NET MAUI?

1.什么是.NET MAUI&#xff1f; .NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架&#xff0c;用于使用 C# 和 XAML 创建本机移动和桌面应用。使用 .NET MAUI&#xff0c;可从单个共享代码库开发可在 Android、iOS、macOS 和 Windows 上运行的应用。 .NET MAUI 是一款…

pytorch中一些最基本函数和类

1.Tensor操作 Tensor是PyTorch中最基本的数据结构&#xff0c;类似于NumPy的数组&#xff0c;但可以在GPU上运行加速计算。 示例&#xff1a;创建和操作Tensor import torch# 创建一个零填充的Tensor x torch.zeros(3, 3) print(x)# 加法操作 y torch.ones(3, 3) z x y pr…

【学习笔记】无人机(UAV)在3GPP系统中的增强支持(三)-机上无线电接入节点无人机

引言 本文是3GPP TR 22.829 V17.1.0技术报告&#xff0c;专注于无人机&#xff08;UAV&#xff09;在3GPP系统中的增强支持。文章提出了多个无人机应用场景&#xff0c;分析了相应的能力要求&#xff0c;并建议了新的服务级别要求和关键性能指标&#xff08;KPIs&#xff09;。…

【JavaEE】AOP实现原理

概述 Spring AOP 是基于动态代理来实现AOP的, 此处主要介绍代理模式和Spring AOP的源码剖析 一.代理模式 代理模式是一种常用的设计模式&#xff0c;它允许为其他对象提供代理&#xff0c;以控制对这个对象的访问。这种结构在不改变原始类的基础上&#xff0c;通过引入代理类…

MongoDB教程(一):Linux系统安装mongoDB详细教程

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、Ubuntu…

应急响应总结

应急响应 日志 windows IIS 6.0 及更早版本&#xff1a; C:\WINDOWS\system32\LogFiles\W3SVC[SiteID]\ IIS 7.0 及更高版本&#xff1a; C:\inetpub\logs\LogFiles\W3SVC[SiteID]\ Apache HTTP Server C:\Program Files (x86)\Apache Group\Apache2\logs\ 或者 C:\Prog…

STFT:解决音频-视频零样本学习 (ZSL) 中的挑战

传统的监督学习方法需要大量的标记训练实例来进行训练,视听零样本学习的任务是利用音频和视频模态对对象或场景进行分类&#xff0c;即使在没有可用标记数据的情况下。为了解决传统监督方法的限制&#xff0c;提出了广义零样本学习&#xff08;Generalized Zero-Shot Learning,…

Golang操作ES全系列(olivere curl操作es)

Golang操作ES全系列&#xff08;olivere & curl操作es&#xff09; &#x1f680;全部代码&#xff08;欢迎&#x1f44f;&#x1f3fb;star&#xff09;&#xff1a; https://github.com/ziyifast/ziyifast-code_instruction/tree/main/go-demo/go-es 1 olivere 创建clie…

html表格账号密码备忘录:表格内容将通过JavaScript动态生成。点击查看密码10秒关闭

<!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><title>账号密码备忘录</title><style>body {background: #2c3e50;text-shadow: 1px 1px 1px #100000;}/* 首页样式开始 */.home_page {color: …

《Linux系统编程篇》Visual Studio Code配置下载,中文配置,连接远程ssh ——基础篇

引言 vscode绝对值得推荐&#xff0c;非常好用&#xff0c;如果你能体会其中的奥妙的话。 工欲善其事&#xff0c;必先利其器 ——孔子 文章目录 引言下载VS Code配置VS Code中文扩展连接服务器 连接服务器测试确定服务器的IP地址VS code 配置ssh信息选择连接到主机选择这个添…

韦东山嵌入式linux系列-驱动设计的思想(面向对象/分层/分离)

1 面向对象 字符设备驱动程序抽象出一个 file_operations 结构体&#xff1b; 我们写的程序针对硬件部分抽象出 led_operations 结构体。 2 分层 上下分层&#xff0c;比如我们前面写的 LED 驱动程序就分为 2 层&#xff1a; ① 上层实现硬件无关的操作&#xff0c;比如注册…