SPRING BOOT发送邮件验证码(Gmail邮箱)
SPRING BOOT邮件发送验证码
一、Gmail邮箱配置
1、进入Gmail(https://mail.google.com)
2、打开谷歌右上角设置

3、启用POP/IMP

4、启用两步验证(https://myaccount.google.com/security)

5、建立应用程式密码

6、复制保存应用程式密码
二、代码
1、引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency>
2、application.properties文件配置
spring.mail.host=smtp.gmail.com
# 邮件服务器端口号
spring.mail.port=587
# 邮件发送方的电子邮件地址
spring.mail.username=你的Gmail邮箱账号
# 邮件发送方的密码或应用程序专用密码(如果启用了两步验证)
spring.mail.password=应用程序专用密码
# 启用TLS加密
spring.mail.properties.mail.smtp.starttls.enable=true
# 验证邮件服务器的身份
spring.mail.properties.mail.smtp.auth=true
# 邮件传输协议
spring.mail.properties.mail.transport.protocol=smtp
3、EmailUtil邮件工具类
@Service
public class EmailUtil implements EmailService
{private final Logger logger = LoggerFactory.getLogger(this.getClass());//Spring Boot 提供了一个发送邮件的简单抽象,使用的是下面这个接口,这里直接注入即可使用@Autowiredprivate JavaMailSender mailSender;// 配置文件中我的谷歌邮箱@Value("${spring.mail.username}")private String from;/*** 简单文本邮件* @param to 收件人* @param subject 主题* @param content 内容*/@Overridepublic void sendSimpleMail(String to, String subject, String content) {//创建SimpleMailMessage对象SimpleMailMessage message = new SimpleMailMessage();//邮件发送人message.setFrom(from);//邮件接收人message.setTo(to);//邮件主题message.setSubject(subject);//邮件内容message.setText(content);//发送邮件mailSender.send(message);}/*** html邮件* @param to 收件人,多个时参数形式 :"xxx@xxx.com,xxx@xxx.com,xxx@xxx.com"* @param subject 主题* @param content 内容*/@Overridepublic void sendHtmlMail(String to, String subject, String content) {//获取MimeMessage对象MimeMessage message = mailSender.createMimeMessage();MimeMessageHelper messageHelper;try {messageHelper = new MimeMessageHelper(message, true);//邮件发送人messageHelper.setFrom(from);//邮件接收人,设置多个收件人地址InternetAddress[] internetAddressTo = InternetAddress.parse(to);messageHelper.setTo(internetAddressTo);//messageHelper.setTo(to);//邮件主题message.setSubject(subject);//邮件内容,html格式messageHelper.setText(content, true);//发送mailSender.send(message);//日志信息logger.info("邮件已经发送。");} catch (Exception e) {logger.error("发送邮件时发生异常!", e);}}/*** 带附件的邮件* @param to 收件人* @param subject 主题* @param content 内容* @param filePath 附件*/@Overridepublic void sendAttachmentsMail(String to, String subject, String content, String filePath) {MimeMessage message = mailSender.createMimeMessage();try {MimeMessageHelper helper = new MimeMessageHelper(message, true);helper.setFrom(from);helper.setTo(to);helper.setSubject(subject);helper.setText(content, true);FileSystemResource file = new FileSystemResource(new File(filePath));String fileName = filePath.substring(filePath.lastIndexOf(File.separator));helper.addAttachment(fileName, file);mailSender.send(message);//日志信息logger.info("邮件已经发送。");} catch (Exception e) {logger.error("发送邮件时发生异常!", e);}}/*** 验证邮箱格式* @param email* @return*/public boolean isEmail(String email) {if (email == null || email.length() < 1 || email.length() > 256) {return false;}Pattern pattern = Pattern.compile("^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$");return pattern.matcher(email).matches();}
}
EmailService
public interface EmailService {/*** 发送文本邮件** @param to 收件人* @param subject 主题* @param content 内容*/void sendSimpleMail(String to, String subject, String content);/*** 发送HTML邮件** @param to 收件人* @param subject 主题* @param content 内容*/public void sendHtmlMail(String to, String subject, String content);/*** 发送带附件的邮件** @param to 收件人* @param subject 主题* @param content 内容* @param filePath 附件*/public void sendAttachmentsMail(String to, String subject, String content, String filePath);
}
4、验证码存储/判断/删除
CodeUtil
@Service
public class CodeUtil {@Autowiredprivate StringRedisTemplate redisTemplate;public String generateVerificationCode() {// 生成6位随机数字验证码return String.valueOf((int) ((Math.random() * 9 + 1) * 100000));}// 验证验证码是否正确public boolean verifyCode(String userId, String code,String key) {key = key + userId;String storedCode = redisTemplate.opsForValue().get(key);return code.equals(storedCode);}//删除redis中验证码public void deleteCode(String userId,String key) {key = key + userId;redisTemplate.delete(key);}
}
存储验证码
//写在需要发送验证码的地方//存储时间private static final int EXPIRATION_TIME_IN_MINUTES = 3;//键名private static final String KEY_PREFIX =="xxx";key=KEY_PREFIX+"123456"
redisTemplate.opsForValue().set(key, 随机数字验证码, EXPIRATION_TIME_IN_MINUTES, TimeUnit.MINUTES);相关文章:
SPRING BOOT发送邮件验证码(Gmail邮箱)
SPRING BOOT邮件发送验证码 一、Gmail邮箱配置 1、进入Gmail(https://mail.google.com) 2、打开谷歌右上角设置 3、启用POP/IMP 4、启用两步验证(https://myaccount.google.com/security) 5、建立应用程式密码 6、复制保存应用程式密码 二、代码 1、引入依赖 <d…...
Liunx安装FTP和SFTP
ftp端口:20/21 sftp端口:22 一、ftp 1、安装ftp yum install vsftpd #安装ftp 服务 (1)查看ftp服务的状态 命令:service vsftpd status PS:提示vsftpd: command not found,修改PATH的环境…...
【Mars3d】new mars3d.layer.GeoJsonLayer({不规则polygon加载label不在正中间的解决方案
问题: 1.new mars3d.layer.GeoJsonLayer({type: "polygon",在styleOptions里配置label的时候,发现这个 不规则polygon加载的时候,会出现label不在中心位置。 graphicLayer new mars3d.layer.GeoJsonLayer({ name: "全国省界…...
怎么快速修复mfc140.dll文件?解决mfc140.dll缺失的方法
面对计算机报告的 mfc140.dll 文件遗失错误,这通常表明系统中缺少一个关键的动态链接库文件,该文件对于运行以 Microsoft Foundation Class (MFC) 库编写的程序十分重要,尤其是那些需要图形界面的应用程序和一些游戏。若没有这个文件&…...
安全防御之入侵检测与防范技术
安全防御中的入侵检测与防范技术主要涉及到入侵检测系统(IDS)和入侵防御技术(IPS)。 入侵检测系统(IDS)是一种对入侵行为自动进行检测、监控和分析的软件与硬件的组合系统。IDS通过从计算机网络或系统中的若…...
Leetcode2807. 在链表中插入最大公约数
Problem: 2807. 在链表中插入最大公约数 文章目录 题目思路注意点Code 题目思路 模拟插入流程: 检测当前节点是否有后置结点;将当前结点与后置结点的值做最大公约数处理得到新结点的值,然后插入到当前结点之后;再将检测结点向后…...
MySQL-DML
DML是数据操纵语言,用来对表中数据进行增删改操纵。 添加数据:INSERT 1.给指定字段添加数据:INSERT INTO 表名(字段名1,字段名2,...)VALUES(值1,值2); 2.给全部字段添加数据:INSERT INTO 表名VALUES(值1,值2) 3.给指定字段批量添…...
开源项目 | 完整部署流程、一款开源人人可用的开源数据可视化分析工具
📚 项目介绍 在互联网数据大爆炸的这几年,各类数据处理、数据可视化的需求使得 GitHub 上诞生了一大批高质量的 BI 工具。 借助这些 BI 工具,我们能够大幅提升数据分析效率、生成更高质量的项目报告,让用户通过直观的数据看到结…...
我建立了一个资源分享群
我建立了一个资源分享群 在为寻找资源犯愁? 在为分享资源犯愁? 一起加入分享资源群(是wx群哦)吧!你可以分享自己的资源帮助他人。你可以在群组里需求资源获取别人的帮助。发广告请绕行,会被拉黑哦 微信…...
C++中几个常用的类型选择模板函数
std::enable_if<B, T>::type 如果编译期满足B,那么返回类型T,否则编译报错 std::conditional<B, T, F>::type 如果编译期满足B,那么返回类型T,否则返回类型F 下面是一个示例,展示如何使用 std::condit…...
【LeetCode】1321. 餐馆营业额变化增长
表: Customer ------------------------ | Column Name | Type | ------------------------ | customer_id | int | | name | varchar | | visited_on | date | | amount | int | ------------------------ 在 SQL 中,(custo…...
【网络技术】【Kali Linux】Wireshark嗅探(八)动态主机配置协议(DHCP)
一、实验目的 本次实验使用 Wireshark (“网鲨”)流量分析工具进行网络流量嗅探,旨在初步了解动态主机配置协议(DHCP协议)的工作原理。 二、DHCP协议概述 动态主机配置协议( D ynamic H ost C onfigurat…...
算法29:不同路径问题(力扣62和63题)--针对算法28进行扩展
题目:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角࿰…...
openGauss学习笔记-188 openGauss 数据库运维-常见故障定位案例-core问题定位
文章目录 openGauss学习笔记-188 openGauss 数据库运维-常见故障定位案例-core问题定位188.1 磁盘满故障引起的core问题188.1.1 问题现象188.1.2 原因分析188.1.3 处理办法 188.2 GUC参数log_directory设置不正确引起的core问题188.2.1 问题现象188.2.2 原因分析188.2.3 处理办…...
kubernetes入门到进阶(5)
目录 镜像仓库:怎么用好docker hub这个宝藏 什么是镜像仓库(Registry) 什么是docker hub 如何在docker hub上挑选镜像 docker hub上进行概念股命名规则是什么 该怎么上传自己的镜像 离线环境该怎么办 小结 镜像仓库:怎么用好docke…...
【字典树Trie】LeetCode-139. 单词拆分
139. 单词拆分。 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。 注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。 示例 1: 输入: s "leetcode&q…...
pytest常用的第三方插件介绍
本节介绍了如何安装和使用第三方插件。如果你想要编写自己的插件,请参阅“编写插件”。 通过pip可以轻松安装第三方插件: pip install pytest-NAME pip uninstall pytest-NAME如果已经安装了插件,pytest会自动找到并集成它,无需手…...
【经验】VSCode连接远程服务器(可以使用git管理、方便查看和编辑Linux源码)
1、查看OpenSSH Windows10通常自带OpenSSH不需要安装。 Windows10下检查是否已经安装OpenSSH的方法: 1)按下快捷键Win + X,选择Windows PoweShell(管理员) 2)输入以下指令: Get-WindowsCapability -Online | ? Name -like ‘OpenSSH*’ 3)如果电脑未安装OpenSSH,…...
机器学习-生存分析:如何基于随机生存森林训练乳腺癌风险评估模型?
一、 引言 乳腺癌是女性最常见的恶性肿瘤之一,也是全球范围内女性死亡率最高的癌症之一。据统计,每年全球有超过200万人被诊断为乳腺癌,其中约60万人死于该疾病。因此,乳腺癌的早期诊断和风险评估对于预防和治疗乳腺癌具有非常重要…...
MySQL学习笔记1: 数据库的简单介绍
目录 1. 数据库是什么2. 数据库这一类软件中的一些典型代表2.1. Oracle2.2. MySQL2.3. SQL Server2.4. SQLite (lite 轻量版) 3. 数据库的类型3.1. 关系型数据库3.2. 非关系型数据库 4. 总结 1. 数据库是什么 数据库是一类软件,这一类软件可以用来管理数据…...
XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
comfyui 工作流中 图生视频 如何增加视频的长度到5秒
comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗? 在ComfyUI中实现图生视频并延长到5秒,需要结合多个扩展和技巧。以下是完整解决方案: 核心工作流配置(24fps下5秒120帧) #mermaid-svg-yP…...
人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型
在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重,适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解,并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...
Pandas 可视化集成:数据科学家的高效绘图指南
为什么选择 Pandas 进行数据可视化? 在数据科学和分析领域,可视化是理解数据、发现模式和传达见解的关键步骤。Python 生态系统提供了多种可视化工具,如 Matplotlib、Seaborn、Plotly 等,但 Pandas 内置的可视化功能因其与数据结…...
