SpringBoot整合Java Mail实现发送邮件

news2024/11/14 2:06:50

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>

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

设计邮件记录日志

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

总结

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

参考

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

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

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

相关文章

TensorBoard ,PIL 和 OpenCV 在深度学习中的应用

重要工具介绍 TensorBoard&#xff1a; 是一个TensorFlow提供的强大工具&#xff0c;用于可视化和理解深度学习模型的训练过程和结果。下面我将介绍TensorBoard的相关知识和使用方法。 TensorBoard 简介 TensorBoard是TensorFlow提供的一个可视化工具&#xff0c;用于&#x…

visual studio开发C++项目遇到的坑

文章目录 1.安装的时候&#xff0c;顺手安装了C模板&#xff0c;导致新建项目执行出问题2.生成的exe&#xff0c;打开闪退问题3.项目里宏的路径不对&#xff0c;导致后面编译没有输出4. vs编译ui&#xff0c;warning跳过&#xff0c;未成功5.vs编译.h&#xff0c;warning跳过&a…

python自动化之用flask校验接口token(把token作为参数)

用到的库&#xff1a;flask 实现效果: 写一个接口&#xff0c;需要token正确才能登录 代码&#xff1a; # 导包 from flask import Flask,request,jsonify,json # 创建一个服务 appFlask(__name__) # post请求&#xff0c;路径&#xff1a;/query app.route(/query, met…

spring boot(学习笔记第十三课)

spring boot(学习笔记第十三课) Spring Security的logout&#xff0c;传统后端开发模式和前后端分离模式的不同&#xff0c;invalidateHttpSession不好用&#xff0c;bug&#xff1f; 学习内容&#xff1a; 传统后端开发模式 vs 前后端分离模式Spring Security的logout功能 1.…

WPF学习(4) -- 数据模板

一、DataTemplate 在WPF&#xff08;Windows Presentation Foundation&#xff09;中&#xff0c;DataTemplate 用于定义数据的可视化呈现方式。它允许你自定义如何展示数据对象&#xff0c;从而实现更灵活和丰富的用户界面。DataTemplate 通常用于控件&#xff08;如ListBox、…

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…

C++进阶(while循环——函数应用)

知识点代码框架总结 输入n组数据 &#xff0c;对n组数据里面的每一组进行处理&#xff08;输出、求和 、运算、其他&#xff09; int n;//几组数据cin >> n;//2while(n--){//对每组数据进行处理}看到下面的样例&#xff0c;肌肉型反映出上面的框架//2// 1 2 3// 4 5 6若…

Golang | Leetcode Golang题解之第233题数字1的个数

题目&#xff1a; 题解&#xff1a; func countDigitOne(n int) (ans int) {// mulk 表示 10^k// 在下面的代码中&#xff0c;可以发现 k 并没有被直接使用到&#xff08;都是使用 10^k&#xff09;// 但为了让代码看起来更加直观&#xff0c;这里保留了 kfor k, mulk : 0, 1;…

二叉搜索树大冒险:寻找-插入-删除

OK&#xff0c;看我们题目就可知道啦&#xff0c;今天要分享学习的一种数据结构就是二叉搜索树。 内容题目也说了三个大概的&#xff0c;分别是寻找、插入、删除。 讲这个之前呢&#xff0c;那么就先讲讲这个二叉搜索树是何方神圣呢&#xff1f; 二叉搜索树&#xff1a; 又…

移动端 火星坐标体系、百度坐标体系和全球坐标体系,该如何选择?

项目场景&#xff1a; 在梳理项目代码时&#xff0c;看到代码中的WGS-84&#xff0c;忽然想起有次面试问我这个问题&#xff0c;今天就好好的梳理下这个问题。 问题描述 移动端获取定位一般用什么编码&#xff1f;为什么要用这个&#xff1f; 原因分析&#xff1a; 解决方案&…

J025_斗地主游戏案例开发(简版)

一、需求描述 完成斗地主游戏的案例开发。 业务&#xff1a;总共有54张牌&#xff1b; 点数&#xff1a;3、4、5、6、7、8、9、10、J、Q、K、A、2 花色&#xff1a;黑桃、红桃、方片、梅花 大小王&#xff1a;大王、小王 点数分别要组合4种花色&#xff0c;大小王各一张。…

LeetCode --- 134双周赛

题目 3206. 交替组 I 3207. 与敌人战斗后的最大分数 3208. 交替组 II 3209. 子数组按位与值为 K 的数目 一、交替组 I & II 题目中问环形数组中交替组的长度为3的子数组个数&#xff0c;主要的问题在于它是环形的&#xff0c;我们要考虑首尾相接的情况&#xff0c;如何…

【流媒体】 通过ffmpeg硬解码拉流RTSP并播放

简介 目前RTSP拉流是网络摄像头获取图片数据常用的方法&#xff0c;但通过CPU软解码的方式不仅延时高且十分占用资源&#xff0c;本文提供了一种从网络摄像头RTSP硬解码的拉流的方法&#xff0c;并且提供python代码以便从网络摄像头获取图片进行后续算法处理。 下载ffmpeg F…

回归求助 教程分享

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 今日 217/10000 抱个拳&#xff0c;送个礼 更多内容&#xff0c;见微*公号往期文章&#xff1a;通透&#xff01;&#xff01;十大回…

Python | Leetcode Python题解之第233题数字1的个数

题目&#xff1a; 题解&#xff1a; class Solution:def countDigitOne(self, n: int) -> int:# mulk 表示 10^k# 在下面的代码中&#xff0c;可以发现 k 并没有被直接使用到&#xff08;都是使用 10^k&#xff09;# 但为了让代码看起来更加直观&#xff0c;这里保留了 kk,…

计算机网络——网络层(IP地址与MAC地址、地址解析协议ARP、IP数据报格式以及转发分组、ICMP、IPV6)

IP地址与MAC地址 由于MAC地址已固化在网卡上的ROM 中&#xff0c;因此常常将 MAC地址称为硬件地址或物理地址&#xff1b;物理地址的反义词就是虚拟地址、软件地址或逻辑地址&#xff0c;IP地址就属于这类地址。 从层次的角度看&#xff0c;MAC地址是数据链路层使用的地址&…

基于lstm的股票Volume预测

LSTM&#xff08;Long Short-Term Memory&#xff09;神经网络模型是一种特殊的循环神经网络&#xff08;RNN&#xff09;&#xff0c;它在处理长期依赖关系方面表现出色&#xff0c;尤其适用于时间序列预测、自然语言处理&#xff08;NLP&#xff09;和语音识别等领域。以下是…

特殊记忆柱群、特殊感觉中枢、强度中枢

智能软件的某些思维状态的标志&#xff0c;能够被一般感觉中枢“先天”感知&#xff0c;或者是与一般感觉中枢“后天”建立记忆联系。在它们建立奖惩记忆联系后&#xff0c;这些思维状态能够兴奋特殊感觉中枢或者一般感觉中枢对应的记忆柱群&#xff0c;也能够被相应感觉中枢的…

【大模型书籍】复旦新出!大规模语言模型:从理论到实践(推荐)

自2018年以来&#xff0c;包含Google、OpenAI、Meta、百度、华为等公司和研究机构都纷纷发布了包括BERT&#xff0c; GPT等在内多种模型&#xff0c;并在几乎所有自然语言处理任务中都表现出色。 今天给大家推荐一本大模型方面的书籍<大规模语言模型&#xff1a;从理论到实…

【数学建模】——力学模型建立的基本理论及方法

目录 一、基本理论 1. 牛顿力学 1.1 牛顿第一定律&#xff08;惯性定律&#xff09; 1.2 牛顿第二定律&#xff08;动力学定律&#xff09; 1.3 牛顿第三定律&#xff08;作用反作用定律&#xff09; 2. 能量守恒定律 2.1 动能和势能 2.2 能量守恒 3. 动量守恒定律…