导读:本期聚焦于苏沐橙创作的《Spring Boot 如何发送 HTML 格式邮件和带附件的邮件?》,敬请观看详情。邮件功能是后台系统里的常见需求,比如注册验证、订单通知、报表推送等。本文围绕 Spring Boot 展开,讲解如何引入 spring-boot-starter-mail 依赖、配置 SMTP 参数,再一步步实现纯文本、HTML 富文本以及带附件邮件的发送。文中给出了完整可运行的代码示例,包括使用 MimeMessageHelper 设置 HTML 内容、添加附件、处理内嵌图片,同时总结了常见的认证失败、乱码、附件损坏等坑点和解决办法,帮你快速把邮件功能落地到项目中。

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

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

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/0916/57856.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。