一、知识点背景

在 SpringBoot 项目中,邮件发送是常见功能(如注册通知、告警推送),但单文本邮件无法满足复杂场景(如带样式的通知、多附件报表)。本文详解SpringBoot 3.x整合JavaMailSender实现多收件人 + HTML 模板 + 附件的完整流程,并解决实际开发中的常见问题。

二、学习过程 & 步骤(图文并茂)

步骤 1:引入核心依赖(pom.xml)

在 SpringBoot 项目中,需引入邮件和模板引擎(Thymeleaf)依赖:

xml

<!-- SpringBoot邮件核心依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- Thymeleaf:用于HTML邮件模板 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

步骤 2:配置邮箱参数(application.yml)

以 QQ 邮箱为例(其他邮箱如网易 / 企业邮箱仅需修改服务器地址):

yaml

spring:
  mail:
    # QQ邮箱SMTP服务器地址
    host: smtp.qq.com
    # SMTP端口(SSL加密)
    port: 465
    # 发件人邮箱
    username: 你的QQ邮箱@qq.com
    # 注意:不是QQ密码,是邮箱“授权码”(需在QQ邮箱设置中开启)
    password: 你的QQ邮箱授权码
    # 加密方式(SSL)
    protocol: smtps
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
            required: true

图 1:QQ 邮箱 “POP3/SMTP 服务” 开启界面(此处建议插入截图:QQ 邮箱→设置→账户→开启 POP3/SMTP 服务的界面)

步骤 3:封装通用邮件工具类

实现多收件人、附件、HTML 模板的复用工具类:

java

运行

package com.example.mail.utils;

import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import java.io.File;

/**
 * SpringBoot邮件发送工具类(支持多收件人、HTML模板、附件)
 */
@Component
public class MailSendUtils {
    private final JavaMailSender mailSender;
    private final TemplateEngine templateEngine;

    // 构造注入(Spring推荐方式)
    public MailSendUtils(JavaMailSender mailSender, TemplateEngine templateEngine) {
        this.mailSender = mailSender;
        this.templateEngine = templateEngine;
    }

    /**
     * 发送带HTML模板+多附件的邮件
     * @param to 收件人列表(如:{"user1@qq.com", "user2@163.com"})
     * @param subject 邮件主题
     * @param templateName Thymeleaf模板名(如:emailTemplate)
     * @param context 模板参数
     * @param attachments 附件列表
     */
    public void sendTemplateMailWithAttach(
            String[] to, String subject, String templateName,
            Context context, File[] attachments
    ) throws MessagingException {
        // 1. 创建MimeMessage(支持多部分内容)
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        // 2. 初始化Helper(true=支持多部分,UTF-8=避免中文乱码)
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8");

        // 3. 设置邮件基础信息
        helper.setFrom("你的QQ邮箱@qq.com"); // 发件人
        helper.setTo(to); // 多收件人
        helper.setSubject(subject); // 主题

        // 4. 渲染Thymeleaf模板为HTML内容
        String htmlContent = templateEngine.process(templateName, context);
        helper.setText(htmlContent, true); // true=内容是HTML

        // 5. 添加多个附件
        if (attachments != null && attachments.length > 0) {
            for (File file : attachments) {
                helper.addAttachment(file.getName(), file);
            }
        }

        // 6. 发送邮件
        mailSender.send(mimeMessage);
    }
}

步骤 4:编写 HTML 邮件模板

resources/templates下创建emailTemplate.html(Thymeleaf 模板):

html

预览

<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>【SpringBoot邮件测试】</title>
    <style>
        .content { color: #333; font-size: 14px; line-height: 1.8; }
        .sign { color: #666; margin-top: 20px; }
    </style>
</head>
<body>
    <div class="content">
        <p>您好,<span th:text="${username}">用户</span>!</p>
        <p>这是一封来自SpringBoot的HTML模板邮件,您的验证码是:<span style="color: #ff4d4f; font-weight: bold;" th:text="${code}">123456</span></p>
    </div>
    <div class="sign">
        <p>—— SpringBoot邮件测试团队</p>
    </div>
</body>
</html>

图 2:Thymeleaf 模板文件目录结构(此处建议插入截图:IDEA 中 resources/templates 下的 emailTemplate.html 位置)

步骤 5:测试邮件发送(Controller 层)

编写接口触发邮件发送:

java

运行

package com.example.mail.controller;

import com.example.mail.utils.MailSendUtils;
import jakarta.mail.MessagingException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.thymeleaf.context.Context;
import java.io.File;

@RestController
public class MailController {
    private final MailSendUtils mailSendUtils;

    public MailController(MailSendUtils mailSendUtils) {
        this.mailSendUtils = mailSendUtils;
    }

    @GetMapping("/sendMail")
    public String sendMail() throws MessagingException {
        // 1. 收件人列表
        String[] to = {"收件人1@qq.com", "收件人2@163.com"};
        // 2. 邮件主题
        String subject = "SpringBoot邮件测试(含模板+附件)";
        // 3. 模板参数
        Context context = new Context();
        context.setVariable("username", "测试用户");
        context.setVariable("code", "888888");
        // 4. 附件(示例:本地的test.txt文件)
        File[] attachments = {new File("D:/test.txt")};

        // 调用工具类发送邮件
        mailSendUtils.sendTemplateMailWithAttach(to, subject, "emailTemplate", context, attachments);
        return "邮件发送成功!";
    }
}

三、遇到的问题 & 解决过程

问题 1:MailAuthenticationException(认证失败)

  • 现象:启动项目调用接口后,控制台报错:Authentication failed
  • 原因
    1. 邮箱未开启 “POP3/SMTP 服务”;
    2. application.ymlpassword填的是 QQ 密码(而非授权码)。
  • 解决步骤
    1. 登录 QQ 邮箱→设置→账户→开启 “POP3/SMTP 服务”;
    2. 生成 “授权码”(需验证手机),将password替换为授权码。

问题 2:附件发送后乱码

  • 现象:收件人收到邮件后,附件名称显示为乱码(如 “????.txt”)。
  • 原因MimeMessageHelper未指定编码格式。
  • 解决步骤:在初始化MimeMessageHelper时,显式指定编码为UTF-8

    java

    运行

    MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
    

问题 3:SocketTimeoutException(连接超时)

  • 现象:调用接口后长时间无响应,最终报错:Connection timed out
  • 原因
    1. 服务器防火墙屏蔽了 SMTP 端口(如 465);
    2. 网络环境限制(如公司内网禁止外部邮件连接)。
  • 解决步骤
    1. 测试端口连通性:用telnet smtp.qq.com 465验证是否能连接;
    2. 若端口不通,联系运维开放端口;或切换为企业内网邮箱。

四、总结 & 最佳实践

核心总结

  1. SpringBoot 邮件发送的核心是JavaMailSender,配合MimeMessageHelper实现复杂邮件;
  2. 多收件人通过helper.setTo(String[] to)实现,附件通过helper.addAttachment()添加;
  3. Thymeleaf 模板需放在resources/templates目录下,通过TemplateEngine渲染为 HTML。

生产环境最佳实践

  1. 异步发送:用@Async注解 + 线程池异步发送,避免阻塞业务线程:

    java

    运行

    // 在工具类方法上添加@Async
    @Async
    public void sendTemplateMailWithAttach(...) { ... }
    
  2. 异常重试:结合Spring Retry实现邮件发送失败重试(避免网络波动导致的单次失败);
  3. 日志记录:记录邮件发送状态(成功 / 失败),便于排查问题。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐