Spring Boot 邮件发送核心模块,支持 普通文本邮件、HTML 富文本邮件、带附件邮件、Thymeleaf 模板邮件 四大高频场景,代码可直接复制复用,适配日常开发中 90%+ 的邮件发送需求。
一、环境配置
1.1 获取邮箱授权码
QQ 邮箱获取方式:
- 登录 QQ 邮箱 → 进入「设置」→「账户」;
- 下滑找到「POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV 服务」;
- 开启「POP3/SMTP 服务」,按提示发送短信验证;
- 验证成功后,系统生成的「授权码」即为 spring.mail.password 的值。
163 邮箱获取方式:
- 登录 163 邮箱 → 进入「设置」→「POP3/SMTP/IMAP」;
- 开启「SMTP 服务」,设置「授权码」(需验证手机);
- 生成的授权码用于配置 spring.mail.password。
1.2 引入spring-boot-starter-mail依赖。
<!--邮件通知-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>3.5.0</version>
</dependency>
<!-- Thymeleaf(用于模板邮件,可选) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
... 其他必要依赖
1.3 application.yaml 邮箱信息配置
spring:
# 邮件配置(其他邮箱如 163、企业邮箱配置类似,仅需修改 host 和授权码)
mail:
host: smtp.qq.com # 邮件服务器地址(QQ邮箱:smtp.qq.com;163邮箱:smtp.163.com)
port: 587 # 端口(SSL端口465,非SSL端口587,推荐587)
username: 1979774006@qq.com #配置邮箱用户名;你自己的邮箱
password: hpsumfzfzgfgeaig #配置申请到的授权码;这里填写刚才短信申请到的授权码
default-encoding: UTF-8 #配置邮件编码
protocol: smtp #协议
properties:
mail:
smtp:
auth: true #开启认证
starttls:
enable: true # 开启STARTTLS加密(适配587端口)
required: true
# Thymeleaf配置(模板邮件用)
thymeleaf:
prefix: classpath:/templates/ # 模板文件存放路径
suffix: .html
mode: HTML
encoding: UTF-8
cache: false # 开发环境关闭缓存,实时生效
# 自定义邮件配置(可选,统一管理收件人、主题前缀等)
email:
default-to: g13345092105@qq.com # 默认收件人
subject-prefix: 【Java技术Demo】 # 邮件主题前缀
按顺序完成如上3个步骤,发送邮件的基础环境配置就弄完了。
二、代码实现
2.1 参数类
定义邮件发送的实体参数
@Data
@ApiModel(value = "邮件发送参数",description = "邮件发送参数DTO")
public class EmailDTO {
@ApiModelProperty("收件人(多个用逗号分隔,如 "a@xxx.com,b@xxx.com")")
private String to;
@ApiModelProperty("邮件主题")
private String subject;
@ApiModelProperty("邮件内容(文本/HTML)")
private String content;
@ApiModelProperty("是否为HTML邮件(true=HTML,false=文本)")
private boolean isHtml;
@ApiModelProperty("附件路径列表(本地文件路径)")
private List<String> attachments;
@ApiModelProperty("模板邮件时,模板名称")
private String templateName;
@ApiModelProperty("模板邮件时,模板参数")
private Object templateData;
}
2.2 核心服务类
通过调用邮件服务实现发送邮件功能
/**
* 邮件发送核心服务:支持文本邮件、HTML邮件、带附件邮件、Thymeleaf模板邮件
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class EmailService {
// 注入Spring邮件发送核心bean(自动配置,无需手动创建)
@Resource
private final JavaMailSender javaMailSender;
// Thymeleaf模板引擎(模板邮件用)
@Resource
private final TemplateEngine templateEngine;
// 发送者邮箱(从配置文件读取)
@Value("${spring.mail.username}")
private String from;
// 默认收件人(从配置文件读取)
@Value("${email.default-to}")
private String defaultTo;
// 邮件主题前缀(从配置文件读取)
@Value("${email.subject-prefix}")
private String subjectPrefix;
/**
* 通用邮件发送方法(统一入口)
*/
public Result<String> sendEmail(EmailDTO emailDTO) {
try {
// 1. 构建MIME消息(支持HTML和附件)
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
// true:支持多部分(附件、HTML)
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
// 2. 基础配置(发件人、收件人、主题)
helper.setFrom(from); // 发件人(必须与配置文件username一致)
helper.setTo(Objects.nonNull(emailDTO.getTo()) ? emailDTO.getTo().split(",") : defaultTo.split(",")); // 收件人(支持多个)
helper.setSubject(subjectPrefix + emailDTO.getSubject()); // 主题(拼接前缀)
// 3. 处理邮件内容(文本/HTML/模板)
if (Objects.nonNull(emailDTO.getTemplateName())) {
// 场景1:模板邮件(Thymeleaf)
Context context = new Context();
context.setVariables((java.util.Map<String, Object>) emailDTO.getTemplateData());
// 渲染模板为HTML内容
String htmlContent = templateEngine.process(emailDTO.getTemplateName(), context);
helper.setText(htmlContent, true); // true:标记为HTML
} else {
// 场景2:文本/HTML邮件
helper.setText(emailDTO.getContent(), emailDTO.isHtml());
}
// 4. 处理附件(如有)
if (Objects.nonNull(emailDTO.getAttachments()) && !emailDTO.getAttachments().isEmpty()) {
for (String attachmentPath : emailDTO.getAttachments()) {
File file = new File(attachmentPath);
if (file.exists()) {
FileSystemResource resource = new FileSystemResource(file);
// 添加附件(参数:附件名称,资源)
helper.addAttachment(file.getName(), resource);
} else {
return Result.fail( "附件不存在:" + attachmentPath);
}
}
}
// 5. 发送邮件
javaMailSender.send(mimeMessage);
log.info("邮件发送成功!收件人:{}", Objects.nonNull(emailDTO.getTo()) ? emailDTO.getTo() : defaultTo);
return Result.ok("邮件发送成功!收件人:" + (Objects.nonNull(emailDTO.getTo()) ? emailDTO.getTo() : defaultTo));
} catch (MessagingException e) {
log.error("邮件发送失败:{}", e.getMessage());
return Result.fail("邮件发送失败:" + e.getMessage());
}
}
// -------------------------- 以下为简化方法(快速调用)--------------------------
/**
* 发送普通文本邮件(简化版)
* 该方法提供了一个简化的接口用于发送纯文本邮件,无需构建复杂的EmailDTO对象
*
* @param to 收件人邮箱地址
* @param subject 邮件主题
* @param content 邮件内容(纯文本)
* @return 返回操作结果,包含发送状态信息
*/
public Result<String> sendTextEmail(String to, String subject, String content) {
// 创建EmailDTO对象并设置邮件基本信息
EmailDTO dto = new EmailDTO();
dto.setTo(to); // 设置收件人地址
dto.setSubject(subject); // 设置邮件主题
dto.setContent(content); // 设置邮件内容
dto.setHtml(false); // 标记为非HTML格式,即纯文本邮件
return sendEmail(dto); // 调用实际发送邮件的方法并返回结果
}
/**
* 发送HTML邮件(简化版)
* 该方法提供了一个简化的接口用于发送HTML格式的邮件
* @param to 收件人邮箱地址
* @param subject 邮件主题
* @param htmlContent HTML格式的邮件内容
* @return 返回操作结果,包含发送状态和信息
*/
public Result<String> sendHtmlEmail(String to, String subject, String htmlContent) {
// 创建EmailDTO对象,用于封装邮件信息
EmailDTO dto = new EmailDTO();
dto.setTo(to); // 设置收件人地址
dto.setSubject(subject); // 设置邮件主题
dto.setContent(htmlContent); // 设置邮件内容(HTML格式)
dto.setHtml(true); // 标记该邮件为HTML格式
return sendEmail(dto); // 调用sendEmail方法发送邮件并返回结果
}
/**
* 发送带附件的邮件(简化版)
* 该方法提供了一个简化的接口用于发送带附件的邮件,内部通过构造EmailDTO对象并调用sendEmail方法实现
*
* @param to 收件人邮箱地址
* @param subject 邮件主题
* @param content 邮件内容
* @param attachments 附件文件路径列表,每个元素代表一个附件的完整路径
* @return 返回Result对象,包含操作结果信息
*/
public Result<String> sendAttachmentEmail(String to, String subject, String content, List<String> attachments) {
// 创建EmailDTO对象并设置基本属性
EmailDTO dto = new EmailDTO();
dto.setTo(to); // 设置收件人
dto.setSubject(subject); // 设置邮件主题
dto.setContent(content); // 设置邮件内容
dto.setHtml(false); // 设置邮件格式为纯文本
dto.setAttachments(attachments); // 设置附件列表
return sendEmail(dto); // 调用sendEmail方法发送邮件并返回结果
}
/**
* 发送Thymeleaf模板邮件(简化版)
* 该方法为发送模板邮件的简化版本,封装了邮件的基本信息
*
* @param to 收件人邮箱地址
* @param subject 邮件主题
* @param templateName Thymeleaf模板名称
* @param templateData 模板所需的数据对象
* @return 返回操作结果,包含邮件发送状态信息
*/
public Result<String> sendTemplateEmail(String to, String subject, String templateName, Object templateData) {
EmailDTO dto = new EmailDTO(); // 创建邮件数据传输对象
dto.setTo(to); // 设置收件人邮箱
dto.setSubject(subject); // 设置邮件主题
dto.setTemplateName(templateName); // 设置模板名称
dto.setTemplateData(templateData); // 设置模板数据
return sendEmail(dto); // 调用邮件发送方法并返回结果
}
}
2.3 模板邮件
在 resources 下新建 templates 目录,并将 html 文件放置其中。
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>模板邮件示例</title>
<style>
.container { width: 80%; margin: 0 auto; padding: 20px; border: 1px solid #eee; border-radius: 8px; }
.title { color: #2c3e50; font-size: 18px; font-weight: bold; margin-bottom: 15px; }
.content { color: #34495e; line-height: 1.8; margin-bottom: 20px; }
.footer { color: #95a5a6; font-size: 14px; text-align: center; margin-top: 30px; }
</style>
</head>
<body>
<div class="container">
<div class="title" th:text="${title}">邮件标题</div>
<div class="content">
<p>尊敬的用户:</p>
<p>您好!您的<span th:text="${bizType}">业务名称</span>已处理完成,详情如下:</p>
<ul>
<li>业务ID:<span th:text="${bizId}">123456</span></li>
<li>处理时间:<span th:text="${handleTime}">2025-11-16 10:00:00</span></li>
<li>处理结果:<span style="color: #27ae60; font-weight: bold;" th:text="${result}">成功</span></li>
</ul>
<p>如有疑问,请联系客服!</p>
</div>
<div class="footer">© 2025 </div>
</div>
</body>
</html>
2.4 使用示例
/**
* 邮件发送测试接口(本地启动后,通过浏览器/Postman调用)
*/
@Slf4j
@RestController
@RequestMapping("/email/test")
@RequiredArgsConstructor
public class EmailTestController {
@Resource
private final EmailService emailService;
/**
* 测试1:发送普通文本邮件
* 访问地址:http://localhost:8080/email/test/sendText
*/
@GetMapping("/sendText")
public Result<String> sendTextEmail() {
return emailService.sendTextEmail(
"1979774006@qq.com", // 收件人
"普通文本邮件测试", // 主题
"这是Spring Boot发送的普通文本邮件,无需复杂配置,简单易用!" // 内容
);
}
/**
* 测试2:发送HTML邮件
* 访问地址:http://localhost:8080/email/test/sendHtml
*/
@GetMapping("/sendHtml")
public Result<String> sendHtmlEmail() {
String htmlContent = """
<h3>HTML邮件测试</h3>
<p>这是一封<span style="color: red; font-weight: bold;">HTML格式</span>的邮件</p>
<p>支持:<br/>
1. 字体样式(颜色、大小、加粗)<br/>
2. 列表<br/>
3. 链接:<a href="https://www.baidu.com">百度一下</a><br/>
</p>
""";
return emailService.sendHtmlEmail(
"1979774006@qq.com",
"HTML邮件测试",
htmlContent
);
}
/**
* 测试3:发送带附件的邮件
* 访问地址:http://localhost:8080/email/test/sendAttachment
*/
@GetMapping("/sendAttachment")
public Result<String> sendAttachmentEmail() {
// 附件本地路径(替换为你的文件路径,如 D:/test.txt、/Users/xxx/test.pdf)
// 获取resources路径
String filePath = this.getClass().getResource("/file").getPath();
log.info("filePath: {}", filePath);
String attachmentPath1 = filePath + "/test.txt";
String attachmentPath2 = filePath +"/test.pdf";
return emailService.sendAttachmentEmail(
"1979774006@qq.com",
"带附件邮件测试",
"这封邮件包含2个附件,请注意查收!",
Arrays.asList(attachmentPath1, attachmentPath2)
);
}
/**
* 测试4:发送Thymeleaf模板邮件
* 访问地址:http://localhost:8080/email/test/sendTemplate
*/
@GetMapping("/sendTemplate")
public Result<String> sendTemplateEmail() {
// 模板参数(与模板文件中的 ${xxx} 对应)
Map<String, Object> templateData = new HashMap<>();
templateData.put("title", "模板邮件测试");
templateData.put("bizType", "用户注册验证");
templateData.put("bizId", "REG20251116001");
templateData.put("handleTime", "2025-11-16 15:30:00");
templateData.put("result", "验证成功");
return emailService.sendTemplateEmail(
"1979774006@qq.com",
"模板邮件测试",
"email-template", // 模板文件名(无需后缀.html)
templateData // 模板参数
);
}
}
到这一个简单的邮件发送服务就实现完成了,我们也可以对他进行一些扩展操作。
三、功能扩展
3.1 异步发送邮件(避免阻塞主线程)
第一步:在启动类添加 @EnableAsync 注解:
@SpringBootApplication
@EnableAsync // 开启异步支持
public class EmailApplication extends BaseDemoApplication {
public static void main(String[] args) {
SpringApplication.run(EmailApplication.class, args);
}
}
第二步:在邮件发送方法上添加 @Async 注解:
@Async // 异步发送
public BaseResponse<String> sendTextEmail(String to, String subject, String content) {
// 原方法逻辑不变
}
或者在发送调用方法时,开启一个新的线程去执行业务方法!
3.2 抄送 / 密送功能
第一步:修改 EmailDTO 新增字段:
@Data
public class EmailDTO {
// 原有字段...
private String cc; // 抄送(多个用逗号分隔)
private String bcc; // 密送(多个用逗号分隔)
}
第二步:在 EmailService.sendEmail 方法中添加:
// 抄送
if (Objects.nonNull(emailDTO.getCc())) {
helper.setCc(emailDTO.getCc().split(","));
}
// 密送
if (Objects.nonNull(emailDTO.getBcc())) {
helper.setBcc(emailDTO.getBcc().split(","));
}