在日常项目开发中,邮件发送是非常通用的功能,常用于用户注册验证码、密码找回、系统消息推送、业务通知、报表发送等场景。SpringBoot 对 Java 原生邮件 API 进行了极致封装,提供了spring-boot-starter-mail自动化依赖,只需简单配置即可快速实现各类邮件发送功能,极大简化了开发流程。
本文将从零开始,手把手讲解 SpringBoot 集成邮件发送,涵盖普通文本邮件、HTML 富文本邮件、带附件邮件、带静态资源邮件四种常用场景,同时解决配置报错、发送失败等常见问题。
一、开发环境准备
本次实战使用稳定通用的开发环境,适配绝大多数 SpringBoot 项目:
- SpringBoot 2.7.x / 3.x 版本(通用适配)
- JDK 1.8+
- Maven 3.6+
- 邮箱账号(本文以 QQ 邮箱为例,网易邮箱、企业邮箱配置逻辑一致)
核心前置准备:获取邮箱授权码
第三方客户端登录邮箱不支持原生密码,必须使用授权码,以 QQ 邮箱为例:
- 登录 QQ 邮箱网页版 → 设置 → 账户
- 开启 POP3/IMAP/SMTP 服务
- 发送短信验证,获取 16 位授权码(妥善保存,仅展示一次)
二、引入 Maven 依赖
在 SpringBoot 项目的 pom.xml 文件中,引入邮件核心启动器,无需额外引入其他冗余依赖:
<!-- SpringBoot 邮件核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- 可选:web依赖,用于测试接口 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
三、全局配置文件配置
在 application.yml 或 application.properties 中配置邮件服务器参数、发送者账号、授权码等核心信息,这是邮件发送的核心配置。
3.1 yml 配置(推荐)
spring:
# 邮件配置
mail:
# SMTP 服务器地址(QQ邮箱:smtp.qq.com,163邮箱:smtp.163.com)
host: smtp.qq.com
# SMTP 端口(SSL加密端口:465,普通端口:25)
port: 465
# 发送者邮箱账号
username: 你的QQ邮箱@qq.com
# 邮箱授权码(重点:不是邮箱登录密码)
password: 你的16位邮箱授权码
# 开启SSL加密(必须配置,否则发送报错)
properties:
mail:
smtp:
ssl:
enable: true
# 关闭域名校验,解决部分环境报错问题
auth: true
starttls:
enable: true
required: true
# 编码格式统一UTF-8,防止中文乱码
default-encoding: UTF-8
3.2 properties 配置
# 邮件服务器配置
spring.mail.host=smtp.qq.com
spring.mail.port=465
spring.mail.username=你的QQ邮箱@qq.com
spring.mail.password=你的16位邮箱授权码
spring.mail.default-encoding=UTF-8
# 开启SSL和认证
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.ssl.enable=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
四、核心代码实战(四种邮件场景)
SpringBoot 提供了 JavaMailSender 核心工具类,自动根据配置文件初始化 Bean,我们直接注入使用即可,无需手动创建邮件连接。
4.1 工具类封装
封装邮件工具类,统一实现四种邮件发送方法,方便业务层直接调用,代码解耦、便于维护:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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.Component;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
/**
* 邮件发送工具类
* 支持:文本邮件、HTML邮件、附件邮件、静态资源邮件
*/
@Component
public class EmailUtil {
// 注入SpringBoot自动配置的邮件发送工具
@Autowired
private JavaMailSender javaMailSender;
// 读取配置文件中的发送者邮箱
@Value("${spring.mail.username}")
private String sendFrom;
/**
* 1. 发送普通文本邮件
* @param to 接收者邮箱
* @param subject 邮件主题
* @param content 邮件文本内容
*/
public void sendSimpleEmail(String to, String subject, String content) {
// 创建简单邮件消息对象
SimpleMailMessage message = new SimpleMailMessage();
// 发送者
message.setFrom(sendFrom);
// 接收者(多个收件人可传数组)
message.setTo(to);
// 邮件主题
message.setSubject(subject);
// 邮件文本内容
message.setText(content);
// 发送邮件
javaMailSender.send(message);
}
/**
* 2. 发送HTML富文本邮件(支持标签、样式、图片排版)
* @param to 接收者邮箱
* @param subject 邮件主题
* @param htmlContent HTML格式内容
* @throws MessagingException 邮件发送异常
*/
public void sendHtmlEmail(String to, String subject, String htmlContent) throws MessagingException {
// 创建复杂邮件消息对象
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
// true 表示开启多文件模式(支持富文本、附件)
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(sendFrom);
helper.setTo(to);
helper.setSubject(subject);
// true 表示内容为HTML格式
helper.setText(htmlContent, true);
javaMailSender.send(mimeMessage);
}
/**
* 3. 发送带附件的邮件
* @param to 接收者邮箱
* @param subject 邮件主题
* @param content 邮件文本内容
* @param filePath 附件本地路径
* @throws MessagingException 邮件发送异常
*/
public void sendAttachEmail(String to, String subject, String content, String filePath) throws MessagingException {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(sendFrom);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content);
// 加载附件文件
FileSystemResource file = new FileSystemResource(new File(filePath));
// 获取文件名
String fileName = file.getFilename();
// 添加附件(参数:附件名称、文件资源)
helper.addAttachment(fileName, file);
javaMailSender.send(mimeMessage);
}
/**
* 4. 发送带静态图片资源的HTML邮件
* @param to 接收者邮箱
* @param subject 邮件主题
* @param htmlContent 带图片占位符的HTML内容
* @param imgPath 图片本地路径
* @param imgId 图片唯一ID(与HTML占位符对应)
* @throws MessagingException 邮件发送异常
*/
public void sendImgHtmlEmail(String to, String subject, String htmlContent, String imgPath, String imgId) throws MessagingException {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(sendFrom);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(htmlContent, true);
// 添加静态图片资源,绑定ID
FileSystemResource img = new FileSystemResource(new File(imgPath));
helper.addInline(imgId, img);
javaMailSender.send(mimeMessage);
}
}
4.2 测试接口编写
编写测试 Controller,启动项目后通过接口快速测试各类邮件发送功能:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.mail.MessagingException;
@RestController
@RequestMapping("/email")
public class EmailController {
@Autowired
private EmailUtil emailUtil;
// 测试发送普通文本邮件
@GetMapping("/send/simple")
public String sendSimple() {
try {
emailUtil.sendSimpleEmail("接收邮箱@qq.com", "SpringBoot测试文本邮件", "Hello SpringBoot 邮件发送!");
return "文本邮件发送成功";
} catch (Exception e) {
return "文本邮件发送失败:" + e.getMessage();
}
}
// 测试发送HTML邮件
@GetMapping("/send/html")
public String sendHtml() {
try {
String html = "<h3 style='color:red'>SpringBoot HTML邮件测试</h3><p>这是富文本邮件,支持样式、字体、颜色排版</p>";
emailUtil.sendHtmlEmail("接收邮箱@qq.com", "SpringBoot测试HTML邮件", html);
return "HTML邮件发送成功";
} catch (MessagingException e) {
return "HTML邮件发送失败:" + e.getMessage();
}
}
// 测试发送带附件邮件
@GetMapping("/send/attach")
public String sendAttach() {
try {
// 替换为本地真实文件路径
String filePath = "D:/test.pdf";
emailUtil.sendAttachEmail("接收邮箱@qq.com", "带附件邮件测试", "您好,本次发送附带附件文件,请查收!", filePath);
return "附件邮件发送成功";
} catch (MessagingException e) {
return "附件邮件发送失败:" + e.getMessage();
}
}
// 测试发送带图片的HTML邮件
@GetMapping("/send/img")
public String sendImg() {
try {
// 图片ID,用于HTML绑定
String imgId = "testImg";
String html = "<h3>带图片的邮件测试</h3><p>本地图片展示:</p><img src='cid:" + imgId + "'/>";
// 替换为本地真实图片路径
String imgPath = "D:/test.png";
emailUtil.sendImgHtmlEmail("接收邮箱@qq.com", "图片邮件测试", html, imgPath, imgId);
return "图片邮件发送成功";
} catch (MessagingException e) {
return "图片邮件发送失败:" + e.getMessage();
}
}
}
五、项目测试运行
- 修改配置文件中的发送邮箱、授权码为自己的真实信息;
- 修改测试接口中的接收邮箱、文件路径、图片路径为真实有效数据;
- 启动 SpringBoot 项目,无报错即配置成功;
- 浏览器访问对应接口,即可完成邮件发送测试。
六、常见报错及解决方案
1. 认证失败 535 error
原因:密码填写错误、未开启 POP3/SMTP 服务、授权码过期
解决:确认填写的是授权码而非登录密码,重新开启邮箱服务并刷新授权码。
2. SSL 连接失败、端口异常
原因:未开启 SSL 加密、端口配置不匹配
解决:465 端口必须开启 SSL,25 端口关闭 SSL,严格对应配置。
3. 邮件中文乱码
原因:编码格式未统一
解决:配置文件指定 default-encoding: UTF-8。
4. 附件文件找不到
原因:文件路径错误、文件不存在、权限不足
解决:使用绝对路径测试,确认文件存在,项目拥有文件读取权限。
七、拓展优化建议
- 异步发送:邮件发送属于 IO 耗时操作,可结合 Spring 的
@Async实现异步发送,不阻塞主线程; - 模板邮件:整合 Thymeleaf / FreeMarker 实现邮件模板,快速制作美观的通知邮件、验证码邮件;
- 异常重试:添加邮件发送失败重试机制,避免网络波动导致发送失败;
- 日志记录:记录邮件发送日志(收件人、主题、发送状态),便于问题排查。
总结
SpringBoot 集成邮件发送核心流程极简:引入依赖 → 配置邮箱服务与授权码 → 注入JavaMailSender → 封装工具类实现不同邮件场景。本文覆盖了项目开发中 99% 的邮件使用场景,代码可直接复用,适配所有 SpringBoot 版本,开箱即用、稳定高效。