Spring Boot整合JavaMail实现邮件发送

一. 发送邮件原理

发件人【设置授权码】 - SMTP协议【Simple Mail TransferProtocol - 是一种提供可靠且有效的电子邮件传输的协议】 - 收件人

二. 获取授权码

开通POP3/SMTP,获取授权码

授权码是QQ邮箱推出的,用于登录第三方客户端的专用密码。适用于登录以下服务:POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务。

温馨提醒:为了你的帐户安全,更改QQ密码以及独立密码会触发授权码过期,需要重新获取新的授权码登录

第一步:进入邮箱设置 -> 账户 -> 生成授权码 :【注意】POP3/SMTP ,IMAP/SMTP服务都需要开启

三. SpringBoot发送邮件步骤

1、导入依赖
<!--对邮件的支持jar-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

2、配置邮箱
spring:
  servlet:
    multipart:
      #设置单个文件大小
      max-file-size: 10MB
      #设置单次请求文件的总大小
      max-request-size: 50MB
  mail:
    host: smtp.qq.com   # 设置邮箱主机(服务商),这里使用QQ邮件服务器
    username:   # 设置用户名 - 发送方
    password:    # 设置密码,该处的密码是QQ邮箱开启SMTP的授权码而非QQ密码
    properties:
      mail:
        smtp:
          auth: true  # 必须进行授权认证,它的目的就是阻止他人任意乱发邮件
          starttls: #SMTP加密方式:连接到一个TLS保护连接
            enable: true
            required: true

3、发送邮件的时候可以自定义发送的内容,创建工具类
@Component
@Slf4j
public class MailUtil {

    /**
     * 1. 来源人名
     * 2. 来源内容
     */
    public static final String originalText = "<hr style=\"border: 1px dashed #ef859d2e;margin: 20px 0\">\n" +
            "            <div>\n" +
            "                <div style=\"font-size: 18px;font-weight: bold;color: #C5343E\">\n" +
            "                    %s\n" +
            "                </div>\n" +
            "                <div style=\"margin-top: 6px;font-size: 16px;color: #000000\">\n" +
            "                    <p>\n" +
            "                        %s\n" +
            "                    </p>\n" +
            "                </div>\n" +
            "            </div>";

    /**
     * 发件人
     */
    public static final String replyMail = "你之前的评论收到来自 %s 的回复";
    public static final String commentMail = "你的文章 %s 收到来自 %s 的评论";
    public static final String messageMail = "你收到来自 %s 的留言";
    public static final String loveMail = "你收到来自 %s 的祝福";
    public static final String imMail = "你收到来自 %s 的消息";
    public static final String notificationMail = "你收到来自 %s 的订阅";

    @Autowired
    private JavaMailSender mailSender;

    @Value("${spring.mail.username}")
    private String sendMailer;

    /**
     * 1. 网站名称
     * 2. 邮件类型
     * 3. 发件人
     * 4. 发件内容
     * 5. originalText
     * 6. 网站名称
     */
    private String mailText;

    @PostConstruct
    public void init() {
        this.mailText = "<div style=\"font-family: serif;line-height: 22px;padding: 30px\">\n" +
                "    <div style=\"display: flex;justify-content: center;width: 100%%;max-width: 900px;background-size: cover;border-radius: 10px\"></div>\n" +
                "    <div style=\"margin-top: 20px;display: flex;flex-direction: column;align-items: center\">\n" +
                "        <div style=\"margin: 10px auto 20px;text-align: center\">\n" +
                "            <div style=\"line-height: 32px;font-size: 26px;font-weight: bold;color: #000000\">\n" +
                "                嘿!你在 %s 中收到一条新消息。\n" +
                "            </div>\n" +
                "            <div style=\"font-size: 16px;font-weight: bold;color: rgba(0, 0, 0, 0.19);margin-top: 21px\">\n" +
                "                %s\n" +
                "            </div>\n" +
                "        </div>\n" +
                "        <div style=\"min-width: 250px;max-width: 800px;min-height: 128px;background: #F7F7F7;border-radius: 10px;padding: 32px\">\n" +
                "            <div>\n" +
                "                <div style=\"font-size: 18px;font-weight: bold;color: #C5343E\">\n" +
                "                    %s\n" +
                "                </div>\n" +
                "                <div style=\"margin-top: 6px;font-size: 16px;color: #000000\">\n" +
                "                    <p>\n" +
                "                        %s\n" +
                "                    </p>\n" +
                "                </div>\n" +
                "            </div>\n" +
                "            %s\n" +
                "            <a style=\"width: 150px;height: 38px;background: #ef859d38;border-radius: 32px;display: flex;align-items: center;justify-content: center;text-decoration: none;margin: 40px auto 0\"\n" +
                "               href=\"https://poetize.cn\" target=\"_blank\">\n" +
                "                <span style=\"color: #DB214B\">有朋自远方来</span>\n" +
                "            </a>\n" +
                "        </div>\n" +
                "        <div style=\"margin-top: 20px;font-size: 12px;color: #00000045\">\n" +
                "            此邮件由 %s 自动发出,直接回复无效(一天最多发送 " + CommonConst.COMMENT_IM_MAIL_COUNT + " 条通知邮件和 " + CommonConst.CODE_MAIL_COUNT + " 条验证码邮件),退订请联系站长。\n" +
                "        </div>\n" +
                "    </div>\n" +
                "</div>";
    }

    public String getMailText() {
        return mailText;
    }
}

4、实现类。一般来说验证码可以应用在注册、登录、找回密码等功能上。前端需要传递flag标志,后端进行判断发送哪种邮件

public Result getCodeForForgetPassword(String place, Integer flag) {
        int i = new Random().nextInt(900000) + 100000;
        if (flag == 1) {
           //  任务需求
        } else if (flag == 2) {
            log.info(place + "---" + "邮箱验证码---" + i);

            List<String> mail = new ArrayList<>();
            mail.add(place);
            String text = getCodeMail(i);
            WebInfo webInfo = (WebInfo) UtopianCache.get(CommonConst.WEB_INFO);

            AtomicInteger count = (AtomicInteger) UtopianCache.get(CommonConst.CODE_MAIL + mail.get(0));
            if (count == null || count.get() < CommonConst.CODE_MAIL_COUNT) {
                mailUtil.sendMailMessage(mail, "您有一封来自" + (webInfo == null ? "Utopian" : webInfo.getWebName()) + "的回信!", text);
                if (count == null) {
                    UtopianCache.put(CommonConst.CODE_MAIL + mail.get(0), new AtomicInteger(1), CommonConst.CODE_EXPIRE);
                } else {
                    count.incrementAndGet();
                }
            } else {
                return Result.fail("验证码发送次数过多,请明天再试!");
            }
        }
        UtopianCache.put(CommonConst.FORGET_PASSWORD + place + "_" + flag, Integer.valueOf(i), 300);
        return Result.success();
    }

首先根据标志为flag参数,这里2为注册时候使用的格式。调用getCodeMail方法获取模板内容

private String getCodeMail(int i) {
        WebInfo webInfo = (WebInfo) UtopianCache.get(CommonConst.WEB_INFO);
        String webName = (webInfo == null ? "Utopian" : webInfo.getWebName());
        return String.format(mailUtil.getMailText(),
                webName,
                String.format(MailUtil.imMail, PoetryUtil.getAdminUser().getUsername()),
                UtopianUtil.getAdminUser().getUsername(),
                String.format(codeFormat, i),
                "",
                webName);
    }

模板内容为:【utopian.cn】%s为本次验证的验证码,请在5分钟内完成验证。为保证账号安全,请勿泄漏此验证码。

对用户点击发送的验证码的次数也需要进行统计,不超过三次,否则进行提示

4、发送邮件

这里采用异步的方式,分别填充邮件主题,邮件内容,发送时间等信息

 @Async
    public void sendMailMessage(List<String> to, String subject, String text) {
        log.info("发送邮件===================");
        log.info("to:{}", JSON.toJSONString(to));
        log.info("subject:{}", subject);
        log.info("text:{}", text);
        try {
            //true代表支持复杂的类型
            MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mailSender.createMimeMessage(), true);
            //邮件发信人
            mimeMessageHelper.setFrom(sendMailer);
            //邮件收信人1或多个
            mimeMessageHelper.setTo(to.toArray(new String[0]));
            //邮件主题
            mimeMessageHelper.setSubject(subject);
            //邮件内容
            mimeMessageHelper.setText(text, true);
            //邮件发送时间
            mimeMessageHelper.setSentDate(new Date());

            //发送邮件
            mailSender.send(mimeMessageHelper.getMimeMessage());

            log.info("发送成功==================");
        } catch (MessagingException e) {
            log.info("发送失败==================");
            log.error(e.getMessage());
        }
    }

image-20231228122738660

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FPGA实现光纤通信(3)——光纤8b/10b编码数据回环

前言 光纤通信属于高速串行通信,具有较高的数据传输速率,通常用于服务器以及通信设备之间用于高速数据交换,对于xilinx 7系列的FPGA,内部具有集成的高速接口用于实现光纤通信。本次就来实现8b/10b编码数据回环。 测试环境:vivado版本:2020.02 FPGA芯片:XC7K70T 测试说…

Linux网络之TCP

Socket编程--TCP TCP与UDP协议使用的套接字接口比较相似, 但TCP需要使用的接口更多, 细节也会更多. 接口 socket和bind不仅udp需要用到, tcp也需要. 此外还要用到三个函数: 服务端 1. int listen(int sockfd, int backlog); 头文件#include <sys/socket.h> 功能: …

如何设计浪漫风格的壁纸

一、选择浪漫的色彩 柔和色调&#xff1a; 粉色系&#xff1a;粉色是浪漫的经典色彩&#xff0c;包括淡粉色、玫瑰粉、樱花粉等&#xff0c;能够营造出温馨和甜蜜的氛围。 紫色系&#xff1a;紫色带有神秘和高贵的感觉&#xff0c;如薰衣草紫、淡紫色等&#xff0c;适合营造浪…

PBFT算法

在我的博客中对于RAFT算法也有详细的介绍&#xff0c;raft算法包含三种角色&#xff0c;分别是&#xff1a;跟随者&#xff08; follower &#xff09;&#xff0c;候选人&#xff08;candidate &#xff09;和领导者&#xff08; leader &#xff09;。集群中的一个节点在某一…

第24篇 基于ARM A9处理器用汇编语言实现中断<六>

Q&#xff1a;怎样设计ARM处理器汇编语言程序使用定时器中断实现实时时钟&#xff1f; A&#xff1a;此前我们曾使用轮询定时器I/O的方式实现实时时钟&#xff0c;而在本实验中将采用定时器中断的方式。新增第三个中断源A9 Private Timer&#xff0c;对该定时器进行配置&#…

深度学习笔记——循环神经网络之LSTM

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍面试过程中可能遇到的循环神经网络LSTM知识点。 文章目录 文本特征提取的方法1. 基础方法1.1 词袋模型&#xff08;Bag of Words, BOW&#xff09;工作…

Linux(Centos、Ubuntu) 系统安装jenkins服务

该文章手把手演示在Linux系统下如何安装jenkins服务、并自定义jenkins数据文件位置、以及jenkins如何设置国内镜像源加速&#xff0c;解决插件下载失败问题 安装方式&#xff1a;war包安装 阿里云提供的war下载源地址&#xff1a;https://mirrors.aliyun.com/jenkins/war/?s…

SQL Server 建立每日自动log备份的维护计划

SQLServer数据库可以使用维护计划完成数据库的自动备份&#xff0c;下面以在SQL Server 2012为例说明具体配置方法。 1.启动SQL Server Management Studio&#xff0c;在【对象资源管理器】窗格中选择数据库实例&#xff0c;然后依次选择【管理】→【维护计划】选项&#xff0…

PHP防伪溯源一体化管理系统小程序

&#x1f50d; 防伪溯源一体化管理系统&#xff0c;品质之光&#xff0c;根源之锁 &#x1f680; 引领防伪技术革命&#xff0c;重塑品牌信任基石 我们自豪地站在防伪技术的前沿&#xff0c;为您呈现基于ThinkPHP和Uniapp精心锻造的多平台&#xff08;微信小程序、H5网页&…

vim如何设置制表符表示的空格数量

:set tabstop4 设置制表符表示的空格数量 制表符就是tab键&#xff0c;一般默认是四个空格的数量 示例&#xff1a; &#xff08;vim如何使设置制表符表示的空格数量永久生效&#xff1a;vim如何使相关设置永久生效-CSDN博客&#xff09;

企业级流程架构设计思路-基于价值链的流程架构

获取更多企业流程资料 纸上得来终觉浅&#xff0c;绝知此事要躬行 一.企业流程分级规则定义 1.流程分类分级的总体原则 2.完整的流程体系需要体现出流程的分类分级 03.通用的流程分级方法 04.流程分级的标准 二.企业流程架构设计原则 1.流程架构设计原则 流程框架是流程体…

刷题总结 回溯算法

为了方便复习并且在把算法忘掉的时候能尽量快速的捡起来 刷完回溯算法这里需要做个总结 回溯算法的适用范围 回溯算法是深度优先搜索&#xff08;DFS&#xff09;的一种特定应用&#xff0c;在DFS的基础上引入了约束检查和回退机制。 相比于普通的DFS&#xff0c;回溯法的优…

【博客之星】年度总结:在云影与墨香中探寻成长的足迹

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、年度回顾 1、创作历程 2、个人成长 3、个人生活与博客事业 二、技术总结 1、赛道选择 2、技术工具 3、实战项目 三、前景与展望 1、云原生未来…

Adobe的AI生成3D数字人框架:从自拍到生动的3D化身

一、引言 随着人工智能技术的发展,我们见证了越来越多创新工具的出现,这些工具使得图像处理和视频编辑变得更加智能与高效。Adobe作为全球领先的创意软件公司,最近推出了一项令人瞩目的新技术——一个能够将普通的二维自拍照转换成栩栩如生的三维(3D)数字人的框架。这项技…

【Nacos】负载均衡

目录 前言 一、服务下线二、权重配置三、同一个集群优先访问四、环境隔离 前言 我们的生产环境相对是比较恶劣的&#xff0c;我们需要对服务的流量进行更加精细的控制.Nacos支持多种负载均衡策略&#xff0c;包括配置权重&#xff0c;同机房&#xff0c;同地域&#xff0c;同环…

回首2024,展望2025

2024年&#xff0c;是个充满挑战与惊喜的年份。在这366个日夜里&#xff0c;我站在编程与博客的交汇点&#xff0c;穿越了无数的风景与挑战&#xff0c;也迎来了自我成长的丰收时刻。作为开发者的第十年&#xff0c;我依然步伐坚定&#xff0c;心中始终带着对知识的渴望与对自我…

net Core Ocelot(1)单地址,多地址

Ocelot 网关技术 》》》配置文件 》》》单地址 {"Routes": [{// 上游 》》 接受的请求//上游请求方法,可以设置特定的 HTTP 方法列表或设置空列表以允许其中任何方法"UpstreamHttpMethod": [ "Get", "Post" ],"UpstreamPathTe…

计算机图形学:实验三 光照与阴影

一、程序功能设计 设置了一个3D渲染场景&#xff0c;支持通过键盘和鼠标控制交互&#xff0c;能够动态调整光源位置、物体材质参数等&#xff0c;具有光照、阴影和材质效果的场景渲染。 OpenGL物体渲染和设置 创建3D物体&#xff1a;代码中通过 openGLObject 结构体表示一个…

22_解析XML配置文件_List列表

解析XML文件 需要先 1.【加载XML文件】 而 【加载XML】文件有两种方式 【第一种 —— 使用Unity资源系统加载文件】 TextAsset xml Resources.Load<TextAsset>(filePath); XmlDocument doc new XmlDocument(); doc.LoadXml(xml.text); 【第二种 —— 在C#文件IO…

JavaScript 数组的map和join方法、延迟函数、location对象、本地存储、正则表达式、箭头函数

数组处理方法 map方法 map方法的作用是遍历数组所有元素&#xff0c;然后执行处理操作&#xff0c;最后返回一个新的数组 语法格式&#xff1a;新数组 原来数组.map(function(ele,index){ ele是数组元素&#xff0c;index是下标 执行完操作之后使用return 返回一个…