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

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: 50MBmail:host: smtp.qq.com   # 设置邮箱主机(服务商),这里使用QQ邮件服务器username:   # 设置用户名 - 发送方password:    # 设置密码,该处的密码是QQ邮箱开启SMTP的授权码而非QQ密码properties:mail:smtp:auth: true  # 必须进行授权认证,它的目的就是阻止他人任意乱发邮件starttls: #SMTP加密方式:连接到一个TLS保护连接enable: truerequired: 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 的订阅";@Autowiredprivate JavaMailSender mailSender;@Value("${spring.mail.username}")private String sendMailer;/*** 1. 网站名称* 2. 邮件类型* 3. 发件人* 4. 发件内容* 5. originalText* 6. 网站名称*/private String mailText;@PostConstructpublic 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、发送邮件

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

 @Asyncpublic 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

相关文章:

Spring Boot整合JavaMail实现邮件发送

一. 发送邮件原理 发件人【设置授权码】 - SMTP协议【Simple Mail TransferProtocol - 是一种提供可靠且有效的电子邮件传输的协议】 - 收件人 二. 获取授权码 开通POP3/SMTP&#xff0c;获取授权码 授权码是QQ邮箱推出的&#xff0c;用于登录第三方客户端的专用密码。适用…...

编辑器Vim基本模式和指令 --【Linux基础开发工具】

文章目录 一、编辑器Vim 键盘布局二、Linux编辑器-vim使用三、vim的基本概念正常/普通/命令模式(Normal mode)插入模式(Insert mode)末行模式(last line mode) 四、vim的基本操作五、vim正常模式命令集插入模式从插入模式切换为命令模式移动光标删除文字复制替换撤销上一次操作…...

K8S极简教程(4小时快速学会)

1. K8S 概览 1.1 K8S 是什么 K8S官网文档&#xff1a;https://kubernetes.io/zh/docs/home/ 1.2 K8S核心特性 服务发现与负载均衡&#xff1a;无需修改你的应用程序即可使用陌生的服务发现机制。存储编排&#xff1a;自动挂载所选存储系统&#xff0c;包括本地存储。Secret和…...

淘宝商品数据解析的应用场景有哪些?

淘宝商品数据解析在多个领域有着广泛的应用场景&#xff0c;以下为你详细介绍&#xff1a; 电商运营与营销 选品分析&#xff1a;通过解析淘宝商品数据&#xff0c;卖家可以了解不同商品的销售情况、价格区间、市场需求热度等信息。例如分析某类商品在不同季节的销量变化&#…...

基于OpenCV实现的答题卡自动判卷系统

一、图像预处理 🌄 二、查找答题卡轮廓 📏 三、透视变换 🔄 四、判卷与评分 🎯 五、主函数 六、完整代码+测试图像集 总结 🌟 在这篇博客中,我将分享如何使用Python结合OpenCV库开发一个答题卡自动判卷系统。这个系统能够自动从扫描的答题卡中提取信…...

计网week1+2

计网 一.概念 1.什么是Internet 节点&#xff1a;主机及其运行的应用程序、路由器、交换机 边&#xff1a;通信链路&#xff0c;接入网链路主机连接到互联网的链路&#xff0c;光纤、网输电缆 协议&#xff1a;对等层的实体之间通信要遵守的标准&#xff0c;规定了语法、语义…...

如何使用tushare pro获取股票数据——附爬虫代码以及tushare积分获取方式

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据 总结 一、Tushare 介绍 Tushare 是一个提供中国股市数据的API接口服务&#xff0c;它允许用户…...

vim的多文件操作

[rootxxx ~]# vim aa.txt bb.txt cc.txt #多文件操作 next #下一个文件 prev #上一个文件 first #第一个文件 last #最后一个文件 快捷键: ctrlshift^ #当前和上个之间切换 说明&#xff1a;快捷键ctrlshift^&#xff0c…...

Mac m1,m2,m3芯片使用nvm安装node14报错

使用nvm安装了node 12/16/18都没有问题&#xff0c;到14就报错了。第一次看到这个报错有点懵&#xff0c;查询资料发现是Mac芯片的问题。 Issue上提供了两个方案&#xff1a; 1、为了在arm64的Mac上安装node 14&#xff0c;需要使用Rosseta&#xff0c;可以通过以下命令安装 …...

【云安全】云原生-Docker(五)容器逃逸之漏洞利用

漏洞利用逃逸 通过漏洞利用实现逃逸&#xff0c;主要分为以下两种方式&#xff1a; 1、操作系统层面的内核漏洞 这是利用宿主机操作系统内核中的安全漏洞&#xff0c;直接突破容器的隔离机制&#xff0c;获得宿主机的权限。 攻击原理&#xff1a;容器本质上是通过 Linux 的…...

认知计算与 AI 大模型:数据仓库、数据湖与数据分析的变革力量

大家好&#xff0c;我是秉寒&#xff0c;今天是龙年腊月 27 了&#xff0c;还有两天就是蛇年除夕了&#xff0c;在此借 CSDN&#xff0c;给大家拜年&#xff01;祝愿大家在新的一年里&#xff0c;技术精进&#xff0c;工作顺遂&#xff0c;代码无 Bug&#xff0c;项目都超神&am…...

JAVA设计模式:依赖倒转原则(DIP)在Spring框架中的实践体现

文章目录 一、DIP原则深度解析1.1 核心定义1.2 现实比喻 二、Spring中的DIP实现机制2.1 传统实现 vs Spring实现对比 三、Spring中DIP的完整示例3.1 领域模型定义3.2 具体实现3.3 高层业务类3.4 配置类 四、Spring实现DIP的关键技术4.1 依赖注入方式对比4.2 自动装配注解 五、D…...

基于微信小程序的健身管理系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…...

Spring Boot是什么及其优点

简介 Spring Boot是基于Spring框架开发的全新框架&#xff0c;其设计目的是简化Spring应用的初始化搭建和开发过程。 Spring Boot整合了许多框架和第三方库配置&#xff0c;几乎可以达到“开箱即用”。 优点 可快速构建独立的Spring应用。 直接嵌入Tomcat、Jetty和Underto…...

Docker 系列之 docker-compose 容器编排详解

文章目录 前言一、Docker-compose简介二、Docker-compose 的安装三、Docker-compose卸载四、Docker-compose常用命令4.1 Docker-compose命令格式4.2 docker-compose up4.3 docker-compose ps4.4 docker-compose stop4.5 docker-compose -h4.6 docker-compose down4.7 docker-co…...

【机器学习】深入探索SVM:支持向量机的原理与应用

目录 &#x1f354; SVM引入 1.1什么是SVM? 1.2支持向量机分类 1.3 线性可分、线性和非线性的区分 &#x1f354; 小结 学习目标 知道SVM的概念 &#x1f354; SVM引入 1.1什么是SVM? 看一个故事&#xff0c;故事是这样子的&#xff1a; 在很久以前的情人节&#xf…...

输入带空格的字符串,求单词个数

输入带空格的字符串&#xff0c;求单词个数 __ueooe_eui_sjje__ ---->3syue__jdjd____die_ ---->3shuue__dju__kk ---->3 #include <stdio.h> #include <string.h>// 自定义函数来判断字符是否为空白字符 int isSpace(char c) {return c || c \t || …...

[STM32 - 野火] - - - 固件库学习笔记 - - -十二.基本定时器

一、定时器简介 STM32 中的定时器&#xff08;TIM&#xff0c;Timer&#xff09;是其最重要的外设之一&#xff0c;广泛用于时间管理、事件计数和控制等应用。 1.1 基本功能 定时功能&#xff1a;TIM定时器可以对输入的时钟进行计数&#xff0c;并在计数值达到设定值时触发中…...

kaggle比赛入门 - House Prices - Advanced Regression Techniques(第二部分)

本文承接上一篇 1. 分析住宅类型&#xff08;BldgType&#xff09;的分布以及它们与销售价格&#xff08;SalePrice&#xff09;的关系 # 1. distribution of dwelling types and their relation to sale prices # BldgType: Type of dwellingdwelling_types df[BldgType].v…...

数字图像处理:实验六

uu们&#xff01;大家好&#xff0c;2025年的新年就要到来&#xff0c;咸鱼哥在这里祝大家在2025年每天开心快乐&#xff0c;天天挣大钱&#xff0c;自由自在&#xff0c;健健康康&#xff0c;万事如意&#xff01;&#xff08;要是咸鱼哥嘴笨的话&#xff0c;还望大家多多包涵…...

C++——list的了解和使用

目录 引言 forward_list与list 标准库中的list 一、list的常用接口 1.list的迭代器 2.list的初始化 3.list的容量操作 4.list的访问操作 5.list的修改操作 6.list的其他操作 二、list与vector的对比 结束语 引言 本篇博客要介绍的是STL中的list。 求点赞收藏评论…...

移动光猫怎么自己改桥接模式?

环境&#xff1a; 型号H3-8s 问题描述&#xff1a; 家里宽带用的是H3-8s 光猫&#xff0c;想改桥接模式。 解决方案&#xff1a; 1.默认管理员账号和密码&#xff1a; 账号&#xff1a;CMCCAdmin 密码&#xff1a;aDm8H%MdAWEB页面我试了登陆不了&#xff0c;显示错误 …...

jupyter配置说明

使用以下命令修改jupyter的配置文件参数&#xff1a; vim /root/.jupyter/jupyter_lab_config.py #这里填写远程访问的IP名&#xff0c;填*则默认是主机IP名 c.ServerApp.ip * # 这里的密码填写上面生成的密钥 c.ServerApp.password ************************************…...

MiniMax-01中Lightning Attention的由来(线性注意力进化史)

目录 引言原始注意力线性注意力因果模型存在的问题累加求和操作的限制Lightning AttentionLightning Attention-1Lightning Attention-2 备注 引言 MiniMax-01: Scaling Foundation Models with Lightning Attention表明自己是第一个将线性注意力应用到如此大规模的模型&#…...

Vue中的动态组件是什么?如何动态切换组件?

什么是动态组件&#xff1f; 动态组件是 Vue.js 中的一项强大功能&#xff0c;它允许开发者根据程序的状态或用户的操作&#xff0c;动态地切换组件。动态组件的优势在于&#xff0c;开发者可以根据具体需求灵活地渲染不同的组件&#xff0c;从而提高应用的通用性和可维护性。…...

Day33:字符串的切片

在 Python 中&#xff0c;**切片&#xff08;Slicing&#xff09;**是对字符串&#xff08;以及其他序列类型&#xff0c;如列表、元组等&#xff09;进行提取部分内容的强大工具。通过切片&#xff0c;你可以非常方便地提取字符串的子字符串、倒序字符串&#xff0c;甚至进行步…...

汽车网络信息安全-ISO/SAE 21434解析(中)

目录 第七章-分布式网络安全活动 1. 供应商能力评估 2. 报价 3. 网络安全职责界定 第八章-持续的网络安全活动 1. 网路安全监控 2. 网络安全事件评估 3. 漏洞分析 4. 漏洞管理 第九章-概念阶段 1. 对象定义 2. 网路安全目标 3. 网络安全概念 第十章 - 产品开发 第十…...

rust feature h和 workspace相关知识 (十一)

feature 相关作用和描述 在 Rust 中&#xff0c;features&#xff08;特性&#xff09; 是一种控制可选功能和依赖的机制。它允许你在编译时根据不同的需求启用或禁用某些功能&#xff0c;优化构建&#xff0c;甚至改变代码的行为。Rust 的特性使得你可以轻松地为库提供不同的…...

从规则到神经网络:机器翻译技术的演进与未来展望

从规则到神经网络:机器翻译技术的演进与未来展望 引言 还记得早些年用翻译软件翻译一句简单的英文句子,却发现翻译结果让人啼笑皆非的日子吗?从“我喜欢吃苹果”被翻译成“我喜欢吃苹果电脑”,到今天的神经网络机器翻译(Neural Machine Translation, NMT)能够生成语义流…...

LLaMA-Factory 微调LLaMA3

LoRA介绍 LoRA&#xff08;Low-Rank Adaptation&#xff09;是一种用于大模型微调的技术&#xff0c; 通过引入低秩矩阵来减少微调时的参数量。在预训练的模型中&#xff0c; LoRA通过添加两个小矩阵B和A来近似原始的大矩阵ΔW&#xff0c;从而减 少需要更新的参数数量。具体来…...