在一个完整的后台系统里,邮件几乎是最常用的通知渠道之一。用户注册后的激活链接、订单支付成功的回执、每天凌晨跑完的报表,这些场景都离不开邮件服务。Spring Boot 对邮件发送做了很好的封装,开发者只需要引入一个 starter 依赖,配置好 SMTP 服务器参数,几行代码就能把邮件发出去。不过实际项目中需求往往不止纯文本这么简单,运营同学会要求邮件带上有排版好看的 HTML 页面,财务系统会要求把生成的 Excel 报表作为附件一起发出来。本文就来完整讲一讲如何在 Spring Boot 中发送 HTML 格式邮件和带附件的邮件,并把常见的坑点一次说清楚。

一、环境准备与基础配置
要在 Spring Boot 中发送邮件,第一步是引入官方提供的邮件启动器。在 pom.xml 中加入如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>这个 starter 底层使用的是 JavaMail(jakarta.mail),Spring 在其之上封装了 JavaMailSender 接口,屏蔽了大量底层细节。引入依赖后,需要在 application.yml 中配置 SMTP 服务器信息。以 QQ 邮箱为例,配置如下:
spring:
mail:
host: smtp.qq.com
port: 465
username: yourname@qq.com
password: 你的授权码
default-encoding: UTF-8
properties:
mail:
smtp:
auth: true
ssl:
enable: true
socketFactory:
port: 465这里有一个非常容易踩的坑需要特别说明:password 填的不是邮箱登录密码,而是 SMTP 授权码。QQ 邮箱、163 邮箱都需要在邮箱设置中开启 SMTP 服务并生成授权码,直接用登录密码会报 535 认证失败的错误。另外端口的选择也有讲究,465 端口走 SSL 加密,587 端口走 STARTTLS,两者配置方式不同,不要混用。如果公司内网使用的是自建邮件服务器,还需要确认证书是否可信,必要时可以配置 mail.smtp.ssl.trust 属性来信任指定主机。
二、发送 HTML 格式邮件
发送 HTML 邮件的核心类是 MimeMessage 和 MimeMessageHelper。简单邮件可以用 SimpleMailMessage,但它只支持纯文本,无法设置 HTML 内容和附件,所以实际项目中基本都直接使用 MimeMessageHelper。下面是一个完整的发送 HTML 邮件的例子:
@Service
public class MailService {
@Autowired
private JavaMailSender mailSender;
@Value("${spring.mail.username}")
private String from;
public void sendHtmlMail(String to, String subject, String htmlContent) {
try {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(htmlContent, true); // 第二个参数 true 表示内容是 HTML
mailSender.send(message);
} catch (MessagingException e) {
throw new RuntimeException("邮件发送失败", e);
}
}
}关键点在 helper.setText(htmlContent, true) 这个重载方法上,第二个参数传 true,JavaMail 才会把内容按 text/html 类型发送,收件方的邮箱客户端才会渲染出排版效果。如果传 false 或者调用只接收一个参数的 setText 方法,收到的就是一堆 HTML 源码字符串。
HTML 内容一般不建议硬编码在 Java 代码里,更优雅的做法是使用模板引擎。引入 Thymeleaf 依赖后,把 HTML 结构写到模板文件中,变量部分用表达式填充,代码和页面彻底分离。示例代码如下:
@Autowired
private TemplateEngine templateEngine;
public void sendTemplateMail(String to, String subject) {
Context context = new Context();
context.setVariable("username", "张三");
context.setVariable("orderNo", "SO20240501001");
String html = templateEngine.process("mail/order-notify", context);
sendHtmlMail(to, subject, html);
}还有一个细节值得注意:HTML 邮件对样式支持非常有限。多数邮箱客户端(尤其是 QQ 邮箱和 Gmail)会过滤掉 <style> 标签和 class 选择器,只保留行内样式。所以写邮件模板时要老老实实用 style 属性写在标签上,用 table 布局代替 flex 布局,图片要写完整的绝对地址,否则渲染出来会面目全非。
三、发送带附件的邮件
带附件的邮件同样依赖 MimeMessageHelper,构造函数的第二个参数 multipart 必须传 true,否则调用 addAttachment 时会直接抛出异常。文件来源可以是本地磁盘,也可以是网络流或者程序运行时动态生成的字节数组,下面分别演示:
public void sendAttachmentMail(String to, String subject, String content,
String filePath) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, true);
// 本地文件作为附件
FileSystemResource file = new FileSystemResource(new File(filePath));
helper.addAttachment(file.getFilename(), file);
mailSender.send(message);
}如果要发送的是内存中的数据,比如刚刚用 POI 生成的 Excel 字节数组,可以使用 addAttachment 的 InputStreamSource 版本,配合 ByteArrayResource 使用。附件文件名如果包含中文,在高版本 JDK 中可能出现乱码,可以通过 EncodeFileName 相关手段处理,或者确保 MimeMessageHelper 构造时明确指定了 UTF-8 编码,实践中指定编码后绝大多数乱码问题都能解决。
补充一个进阶场景:如果希望图片直接嵌在 HTML 正文里显示而不是以附件形式存在,可以使用 addInline 方法,并在 HTML 中用 cid 协议引用:
// 后端添加内嵌图片
helper.addInline("logoImage", new FileSystemResource(new File("D:/files/logo.png")));
// HTML 模板中的引用方式
// <img src="cid:logoImage" width="200" />注意 addInline 的资源要放在 setText 之后添加,并且内容 ID 两边要保持一致,否则图片会显示成红叉。内嵌图片和附件的区别在于 Disposition 类型不同,前者是 inline,后者是 attachment,收件端展示方式完全不同。
四、常见问题排查与最佳实践
邮件发送看似简单,实际踩坑的人不在少数,这里集中梳理几个高频问题。第一个是 535 认证失败,九成原因是密码填了登录密码而不是授权码,剩下的可能是账号没开通 SMTP 服务。第二个是发送成功但收不到,先去垃圾箱找找,再检查发件内容是否触发了反垃圾规则,正文里大量链接、全图片无文字的邮件很容易被判为垃圾邮件。第三个是 HTML 显示异常,多半是样式被客户端过滤了,按前面说的行内样式方案改写模板即可。
从工程角度还有几点建议。发送邮件属于 IO 操作,耗时不可控,强烈建议放在异步线程或者消息队列消费者中执行,避免拖慢主业务接口;可以配合 @Async 注解加线程池实现。生产环境要做好异常捕获和重试机制,网络抖动导致的偶发失败很常见,简单的三次重试能显著提升成功率。另外建议对邮件发送做日志埋点,记录收件人、主题、发送结果,方便后续排查用户反馈的收不到邮件问题。最后一点,SMTP 账号信息属于敏感配置,不要明文提交到代码仓库,可以用环境变量或者配置中心管理,不同环境(开发、测试、生产)使用不同的发件账号,避免测试邮件污染线上通道。
到这里,Spring Boot 发送 HTML 邮件和附件邮件的完整流程就讲完了。核心记住两点:MimeMessageHelper 的 multipart 参数设为 true,setText 的 html 参数设为 true,剩下的就是模板编写和运维层面的细节打磨。把文中的示例代码稍作改造,就能直接用到自己的项目里。
Spring Boot邮件发送HTML邮件附件邮件修改时间:2026-09-16 09:32:49