SpringBoot整合(三)SpringBoot发送邮件
使用SpringBoot发送邮件
邮件发送其实是一个非常常见的需求,用户注册,找回密码等地方,都会用到,Spring Boot 中对于邮件发送,提供了相关的自动化配置类,使得邮件发送变得非常容易。
1、前置工作
目前国内大部分的邮件服务商都不允许直接使用用户名/密码的方式来在代码中发送邮件,都是要先申请授权码,这里以 QQ 邮箱为例,向大家演示授权码的申请流程:
首先我们需要先登录 QQ 邮箱网页版,点击上方的设置按钮:然后点击账户选项卡:在账户选项卡中找到开启POP3/SMTP选项,如下:

点击开启,开启相关功能,开启过程需要手机号码验证,按照步骤操作即可,不赘述。开启成功之后,即可获取一个授权码,将该号码保存好,一会使用。
2、引入依赖、配置邮箱基本信息
<!--集成发送邮件的功能-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId>
</dependency>
然后在yml配置文件中进行配置
spring:mail:host: smtp.qq.com # 设置邮箱主机port: 587 # SMTP 服务器的端口username: yyds@qq.com # 设置用户名password: yyds # 设置密码,该处的密码是QQ邮箱开启SMTP的授权码而非QQ密码mail:from: ${spring.mail.username}to: yyds@163.com
做完这些之后,Spring Boot 就会自动帮我们配置好邮件发送类,相关的配置在
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration 类中,部分源码如下:
@Configuration
@ConditionalOnClass({ MimeMessage.class, MimeType.class, MailSender.class })
@ConditionalOnMissingBean(MailSender.class)
@Conditional(MailSenderCondition.class)
@EnableConfigurationProperties(MailProperties.class)
@Import({ MailSenderJndiConfiguration.class, MailSenderPropertiesConfiguration.class })
public class MailSenderAutoConfiguration {}
可以看到,导入了另外一个配置 MailSenderPropertiesConfiguration 类,这个类中,提供了邮件发送相关的工具类,源码如下:
@Configuration
@ConditionalOnProperty(prefix = "spring.mail", name = "host")
class MailSenderPropertiesConfiguration {private final MailProperties properties;MailSenderPropertiesConfiguration(MailProperties properties) {this.properties = properties;}@Bean@ConditionalOnMissingBeanpublic JavaMailSenderImpl mailSender() {JavaMailSenderImpl sender = new JavaMailSenderImpl();applyProperties(sender);return sender;}
}
可以看到,这里创建了一个 JavaMailSenderImpl 的实例, JavaMailSenderImpl 是 JavaMailSender 的一个实现,我们将使用 JavaMailSenderImpl 来完成邮件的发送工作。
3、Service层代码
自定义的MailProperties配置类,用于解析mail开头的配置属性
package com.yyds.domain;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Data
@Component
@ConfigurationProperties(prefix = "mail")
public class MailProperties {private String from;private String to;}
service层
package com.yyds.service;import freemarker.template.TemplateException;import javax.mail.MessagingException;
import java.io.IOException;
import java.util.Map;public interface MailService {void sendSimpleMail(String subject, String text) ;void sendHtmlMail(String subject, String text, Map<String, String> attachmentMap) throws MessagingException;void sendTemplateMail(String subject, Map<String, Object> params) throws MessagingException, IOException, TemplateException;
}
package com.yyds.service.impl;import com.yyds.domain.MailProperties;
import com.yyds.service.MailService;
import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.io.IOException;
import java.util.Map;@Service
public class MailServiceImpl implements MailService {@Autowiredprivate JavaMailSender javaMailSender;@Autowiredprivate MailProperties myMailProperties;/*** 发送简单文本邮件*/@Overridepublic void sendSimpleMail(String subject, String text) {SimpleMailMessage mailMessage = new SimpleMailMessage();mailMessage.setFrom(myMailProperties.getFrom());mailMessage.setTo(myMailProperties.getTo());mailMessage.setSubject(subject);mailMessage.setText(text);javaMailSender.send(mailMessage);}/*** 发送带有链接和附件的复杂邮件*/@Overridepublic void sendHtmlMail(String subject, String text, Map<String, String> attachmentMap) throws MessagingException {MimeMessage mimeMessage = javaMailSender.createMimeMessage();//是否发送的邮件是富文本(附件,图片,html等)MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);messageHelper.setFrom(myMailProperties.getFrom());messageHelper.setTo(myMailProperties.getTo());messageHelper.setSubject(subject);messageHelper.setText(text, true);//重点,默认为false,显示原始html代码,无效果if(attachmentMap != null){attachmentMap.entrySet().stream().forEach(entrySet -> {try {File file = new File(entrySet.getValue());if(file.exists()){messageHelper.addAttachment(entrySet.getKey(), new FileSystemResource(file));}} catch (MessagingException e) {e.printStackTrace();}});}javaMailSender.send(mimeMessage);}/*** 发送模版邮件*/@Overridepublic void sendTemplateMail(String subject, Map<String, Object> params) throws MessagingException, IOException, TemplateException {MimeMessage mimeMessage = javaMailSender.createMimeMessage();MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);helper.setFrom(myMailProperties.getFrom());helper.setTo(myMailProperties.getTo());freemarker.template.Configuration configuration = new freemarker.template.Configuration(freemarker.template.Configuration.VERSION_2_3_19);TemplateLoader templateLoader = new ClassTemplateLoader(this.getClass(), "/templates/");configuration.setTemplateLoader(templateLoader);Template template = configuration.getTemplate("mail.ftl");String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, params);helper.setSubject(subject);helper.setText(html, true);//重点,默认为false,显示原始html代码,无效果javaMailSender.send(mimeMessage);}
}
4、发送邮件
4.1 测试发送简单文本邮件
@SpringBootTest(classes = BootStartApplication.class)
public class MimeMailTest {@Autowiredprivate MailService mailService;@Testpublic void sendMail() {mailService.sendSimpleMail("测试Springboot发送邮件", "发送邮件...");}
}

4.2 测试发送带有链接和附件的复杂邮件
package com.yyds;import com.yyds.service.MailService;
import freemarker.template.TemplateException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import javax.mail.MessagingException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;@SpringBootTest(classes = BootStartApplication.class)
public class MimeMailTest {@Autowiredprivate MailService mailService;@Testpublic void testMail() throws MessagingException {Map<String, String> attachmentMap = new HashMap<>();attachmentMap.put("附件", "D:\\D_ENL_MRO数据统计.xlsx");mailService.sendHtmlMail("测试Springboot发送带附件的邮件2", "欢迎进入<a href=\"http://www.baidu.com\">百度首页</a>", attachmentMap);}}

4.3 测试发送发送模版邮件
首先需要引入 Freemarker 依赖:
<!--整合freemarker--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency>
然后在 resources/templates 目录下创建一个 mail.ftl 作为邮件发送模板:

<html><body><h3>你好, <span style="color: red;">${username}</span>, 这是一封模板邮件!</h3></body>
</html>
package com.yyds;import com.yyds.service.MailService;
import freemarker.template.TemplateException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import javax.mail.MessagingException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;@SpringBootTest(classes = BootStartApplication.class)
public class MimeMailTest {@Autowiredprivate MailService mailService;@Testpublic void testFreemarkerMail() throws MessagingException, IOException, TemplateException {Map<String, Object> params = new HashMap<>();params.put("username", "Tom");mailService.sendTemplateMail("测试Springboot发送模版邮件", params);}}

相关文章:
SpringBoot整合(三)SpringBoot发送邮件
使用SpringBoot发送邮件 邮件发送其实是一个非常常见的需求,用户注册,找回密码等地方,都会用到,Spring Boot 中对于邮件发送,提供了相关的自动化配置类,使得邮件发送变得非常容易。 1、前置工作 目前国内…...
【docker知识】联合文件系统(unionFS)原理
一、说明 Docker CLI 操作起来比较简单——您只需掌握Create、Run、InspPull和Push容器和图像,但是谁想过Docker 背后的内部机制是如何工作的?在这个简单的表象背后隐藏着许多很酷的技术, UnionFS(统一文件系统)就是其…...
使用Lame库实现wav、pcm转mp3
文章目录 前言 一、Lame库是什么? 二、使用步骤 0.创建native项目 1.下载Lame库 2.pcm转MP3 3.wav转MP3 4、native方法如下 三、注意 总结 前言 因为使用android录音后生成的文件是wav或者pcm格式,项目要求最后的文件需要是mp3格式,于…...
c++11 标准模板(STL)(std::multimap)(三)
定义于头文件 <map> template< class Key, class T, class Compare std::less<Key>, class Allocator std::allocator<std::pair<const Key, T> > > class multimap;(1)namespace pmr { template <class Key, class T…...
【报复性赚钱】2023年5大风口行业
今天就来和大家分享一下,在时代的洪流下,普通人如何顺应大势抓住机遇! 实现人在风口上,猪都会飞起来。 根据对市场的观察及各平台数据分析结果,结合国家政策和经济专家的分析,小编预测了2023年将会迎来大…...
单目相机、双目相机和RGB-D相机学习笔记(一些视频和博文网址)
目录1. 单目相机1.1 摄像头原理1.2 单目相机的标定2 双目相机2.1 双目相机定位原理2.2 双目相机的缺陷3 RGB-D相机3.1 深度相机结构光原理3.2 RGB-D相机的应用1. 单目相机 1.1 摄像头原理 视频网址:【全网最详细】摄像头原理分析(约25分钟课程…...
word和wps添加mathtype选项卡
word或wps添加mathtype选项卡 前提 安装好word或wps安装好mathtype 步骤 确认word或wps具体安装位置确认word或wps位数为32位还是64位复制mathtype中的MathPage.wll文件和MathType Commands 2016.dotm文件到STARTUP位置添加受信任位置添加加载项 安装位置 通过开始页面&a…...
获取成员userID
文章目录一、简介二、获取token1、获取秘钥2、获取Token三、获取部门数据1、获取部门列表2、获取子部门ID列表3、获取单个部门详情四、获取成员信息1、读取成员2、获取部门成员3、获取部门成员详情一、简介 同步数据到企微: 企业如果需要从自有的系统同步通讯录到…...
DOM编程-显示网页时钟
<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>显示网页时钟</title> </head> <body bgcolor"antiquewhite"> <script type"text/javascrip…...
浅谈保护数据的加密策略
加密是一种将信息从可读格式转换为混乱字符串的技术。这样做可以防止数据传输中的机密数据泄露。文档、文件、消息和所有其他形式的网络通信都可以加密。加密策略和身份验证服务的结合,还能保障企业机密信息只对授权用户开启访问权限。常见的数据加密包括以下两种&a…...
Java中String,StringBuffer和StringBuilder
String类 我们在定义string变量时 常常写 String str "hello word"; 这样的代码,看起来和int a 0; 是一样的声明方式, 但其实两者是不同的, int 是java中定义的基本数据类型, 而String是一个类,是一个特殊的类,可以像基本数据类型一样直接赋…...
华为认证常见技术问答整理:什么是Datacom认证?
一、关于Datacom认证Q:什么是Datacom认证?A:Datacom,即DatacomCommunication的缩写,中文为“数据通信”,属于ICT技术架构认证类别(华为认证包含ICT技术架构认证、平台与服务认证和行业ICT认证三…...
Read book Netty in action (Chapter II) (Netty Introduction)
前言 支持15W的并发客户端,我们应该视为理所当然的事情,很多公司甚至能够支撑更多,例如我们熟知的 BAT,当几年前双十一的夜晚,并发量是不可估计的。还有春节的时候购票的时候的并发。作为一个优秀的开发人员ÿ…...
python--route
routes是用python重新实现的Rails routes系统,用于将url映射到应用程序的actions ,并反过来生成url 它也是在openstack实现restful通信的方式,它被用来做将 URL 映射为 App 的 action,以及为 App的action 产生 URL 两个重要的方法…...
java面试中被问到项目中的难点,怎么回答
java面试中被问到项目中的难点,怎么回答回答步骤举例说明回答步骤 回答这个问题的方法取决于你的项目的类型和难度。 但是,一般来说,你可以遵循以下步骤来回答这个问题: 描述你的项目:首先简要描述你的项目的类型和目…...
【速通版】吴恩达机器学习笔记Part1
准备速通一下吴恩达的机器学习 很快做个笔记5.2.3 监督学习 part 2_哔哩哔哩_bilibili 目录 1.概述(P1-P3) 2.supervised learning:(P4,P5) regression: classification 3.unsupervised learning (P6- 1.聚类算…...
面试(九)小米C++开发一面 21.11.02
1、局部变量与全局变量的区别?可以同名嘛? 首先是作用域: 局部变量只在变量声明的代码块范围内生效 全局变量在其声明后的所有位置都能访问到 在局部变量与全局变量同名的情况下,全局变量会被屏蔽掉,只会使用局部变量的内容 2、extern 当在a.c中想要使用b.c中的函数fu…...
儿童书写台灯哪个牌子比较好?2023儿童护眼台灯分享
现在儿童的近视率高达52.7%,有科技水平的提高和电子产品的普及,近视率逐年攀升,出现低龄化现象,调查结果显示,其中6岁儿童达到14.3%,小学生为35.6%。初中生71.1%,高中生高达80.5%,可…...
市场调研计划书如何写?
想要做好一个产品,市场调研是必不可少的一步,也是第一步,那么如何进行市场调研呢?以下是我整理的一份市场调研计划书,希望能够帮助到大家!!! 一、文档版本控制 主要记录文档的版本…...
python网络爬虫—快速入门(理论+实战)(七)
系列文章目录 (1)python网络爬虫—快速入门(理论实战)(一) (2)python网络爬虫—快速入门(理论实战)(二) (3) p…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...
