SpringBoot 邮件发送:文本邮件与 HTML 邮件

在SpringBoot 项目中,邮件发送是不可或缺的基础功能,广泛应用于用户注册验证、密码找回、系统告警、订单通知等核心场景。SpringBoot 提供的 spring-boot-starter-mail 组件,基于 JavaMail 完成了底层协议封装与自动化配置,无需开发者手动处理 SMTP 连接、编码适配等繁琐操作。

一、核心基础

    1. 协议说明:发送邮件的核心依赖是SMTP 协议(Simple Mail Transfer Protocol,简单邮件传输协议),负责将邮件从发件人服务器传递到收件人服务器。推荐使用加密端口 587(TLS 加密),安全性更高,可有效避免邮件被拦截或篡改;非加密端口 25 因易被垃圾邮件利用,多数服务器已屏蔽,不推荐使用。
    1. 核心组件详解(Spring 自动注入,无需手动实例化):
  • JavaMailSender:邮件发送的核心接口,封装了邮件发送的所有核心操作(连接服务器、发送邮件、关闭连接等),SpringBoot 会根据配置文件自动创建实例。

  • SimpleMailMessage:专门用于发送纯文本邮件的工具类,用法简洁,仅支持文本内容、收件人、主题等基础配置,不支持样式、附件。

  • MimeMessageHelper:复杂邮件的辅助工具类,简化 HTML 邮件、带附件邮件、多收件人(抄送/密送)等场景的配置,解决中文乱码、样式解析等常见问题。

    1. 核心应用场景:
  • • 纯文本邮件:适用于系统告警、简单通知(如服务器异常提醒、操作日志通知),特点是简洁、发送速度快,无需复杂样式。

  • • HTML 富文本邮件:适用于用户交互类场景(如注册验证码、密码找回、订单通知、活动营销),支持文字样式、图片、链接、表格等,提升用户体验,是实际开发中最常用的邮件类型。

二、环境准备(关键步骤,缺一不可)

发送邮件前,必须开启发件人邮箱的 SMTP 服务,并获取「授权码」------ 授权码是第三方应用(如 SpringBoot 项目)访问邮箱的专用密钥,不同于邮箱登录密码,目的是保障邮箱账号安全,防止密码泄露。不同邮箱的开启方式略有差异,以下是最常用的两种邮箱操作步骤,详细且可直接对照操作。

1. QQ邮箱

    1. 登录 QQ 邮箱网页版(https://mail.qq.com/),点击顶部导航栏的「设置」,选择左侧「账户」选项;
    1. 下拉页面,找到「POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务」模块,点击「开启POP3/SMTP服务」;
    1. 根据提示,用绑定 QQ 邮箱的手机发送短信验证,验证通过后,系统会自动生成一串授权码,复制并保存(建议存放在配置文件中,丢失可重新生成);
    1. 记住 QQ 邮箱的 SMTP 服务器地址:smtp.qq.com,推荐使用端口:587(TLS 加密),若 587 端口不可用,可切换为 465(SSL 加密)。

2. 163邮箱

    1. 登录 163 邮箱网页版(https://mail.163.com/),点击顶部「设置」,选择「POP3/SMTP/IMAP」选项;
    1. 在「SMTP 服务」模块,点击「开启」,若未设置过授权码,需先设置授权码(建议设置复杂密码,与邮箱登录密码区分开),设置完成后保存;
    1. 163 邮箱的 SMTP 服务器地址:smtp.163.com,推荐端口:587(TLS 加密),465(SSL 加密)同样支持,可根据服务器环境选择。

三、SpringBoot 集成配置

SpringBoot 对邮件发送进行了自动化配置,仅需引入核心依赖、配置相关参数,即可快速集成,无需编写额外的配置类(特殊场景除外)。

1. 核心依赖(pom.xml)

仅需引入邮件核心 starter,lombok 用于简化代码(可选但推荐,可避免编写 getter/setter、日志输出等冗余代码),无需引入其他额外依赖。

go 复制代码
<!-- SpringBoot 邮件发送核心依赖,自动引入 JavaMail 相关依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

<!-- 可选:lombok,简化代码,无需写getter/setter、log日志等 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional> <!-- 可选依赖,不影响其他模块 -->
</dependency>

<!-- 可选:spring-boot-starter-web,用于提供测试接口,若项目已引入可忽略 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2. 单邮箱配置(application.yml)

配置发件人邮箱、授权码、SMTP 服务器地址、编码格式、超时时间等核心参数,注释清晰,可直接替换为自己的邮箱信息,避免因配置错误导致发送失败。

go 复制代码
spring:
  mail:
    # 发件人邮箱地址(QQ/163/企业邮箱均可,需与下方SMTP地址对应)
    username: 123456@qq.com
    # 授权码(不是邮箱登录密码!是上一步获取的第三方应用授权码)
    password: abcdefghijklmnop
    # SMTP 服务器地址(对应邮箱,不可写错,QQ邮箱:smtp.qq.com;163邮箱:smtp.163.com)
    host: smtp.qq.com
    # 编码格式,固定为 UTF-8,避免邮件标题、内容出现中文乱码
    default-encoding: UTF-8
    # 额外配置:解决超时、加密、认证等问题,生产环境必配
    properties:
      mail:
        smtp:
          # 必须开启 SMTP 认证(true),否则邮箱服务器会拒绝发送请求
          auth: true
          # 开启 TLS 加密,提升邮件发送安全性,避免邮件被拦截
          starttls:
            enable: true
            required: true # 强制使用 TLS 加密
          # 邮件发送端口,推荐 587(TLS),465(SSL)也可,需与加密方式对应
          port: 587
        # 超时设置(单位:毫秒),避免网络波动、服务器响应慢导致发送超时
        timeout: 10000 # 邮件发送超时时间
        connectiontimeout: 10000 # 连接服务器超时时间
        writetimeout: 10000 # 写入数据超时时间

# 日志配置(可选,用于排查邮件发送问题,开发环境建议开启)
logging:
  level:
    # 开启 Spring 邮件发送相关日志,DEBUG 级别可查看完整发送流程
    org.springframework.mail: DEBUG
    # 开启自定义邮件相关日志(替换为自己的包名)
    com.example.mail: INFO

四、核心代码

采用「工具类封装 + 接口测试」的模式,将邮件发送逻辑封装为通用工具类,便于在项目中复用;提供测试接口,可快速验证邮件发送功能,同时补充异常处理、日志输出,确保代码的健壮性。

1. 封装邮件工具类 MailUtil

整合纯文本邮件、HTML 富文本邮件的发送方法,支持单收件人、多收件人,添加异常捕获和日志记录,避免发送失败影响主流程;同时补充代码注释,便于后续维护和修改。

go 复制代码
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
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;

/**
 * 邮件发送工具类(聚焦文本、HTML 两种常用邮件,适配多场景复用)
 * 注:工具类使用 @Component 注解,交给 Spring 管理,可在 Service、Controller 中直接注入使用
 */
@Slf4j // lombok 注解,自动生成 log 日志对象,无需手动创建
@Component
@RequiredArgsConstructor // lombok 注解,自动注入构造方法,无需写 @Autowired
public class MailUtil {

    // 核心发送接口,SpringBoot 自动根据配置文件创建实例,直接注入即可
    private final JavaMailSender javaMailSender;

    // 从 application.yml 配置文件中读取发件人邮箱,无需硬编码
    @Value("${spring.mail.username}")
    private String defaultFromMail;

    // 1. 发送纯文本邮件(重载方法,支持单收件人、多收件人,适配不同场景)
    /**
     * 单收件人文本邮件
     * @param to 收件人邮箱地址(单个)
     * @param subject 邮件主题
     * @param content 邮件纯文本内容
     */
    public void sendTextMail(String to, String subject, String content) {
        sendTextMail(new String[]{to}, subject, content);
    }

    /**
     * 多收件人文本邮件
     * @param to 收件人邮箱地址数组(多个)
     * @param subject 邮件主题
     * @param content 邮件纯文本内容
     */
    public void sendTextMail(String[] to, String subject, String content) {
        try {
            // 创建纯文本邮件实例
            SimpleMailMessage message = new SimpleMailMessage();
            message.setFrom(defaultFromMail); // 设置发件人(从配置文件读取,避免硬编码)
            message.setTo(to); // 设置收件人(可单个、可多个)
            message.setSubject(subject); // 设置邮件主题
            message.setText(content); // 设置邮件纯文本内容
            javaMailSender.send(message); // 发送邮件
            log.info("纯文本邮件发送成功,收件人:{},邮件主题:{}", String.join(",", to), subject);
        } catch (Exception e) {
            // 捕获所有异常,记录日志,避免影响主流程
            log.error("纯文本邮件发送失败,收件人:{},邮件主题:{},异常信息:{}", 
                    String.join(",", to), subject, e.getMessage(), e);
            // 抛出运行时异常,由调用方根据业务需求处理(如重试、返回错误信息)
            throw new RuntimeException("文本邮件发送失败,请稍后重试", e);
        }
    }

    // 2. 发送 HTML 富文本邮件(重载方法,支持单收件人、多收件人,带样式)
    /**
     * 单收件人 HTML 邮件
     * @param to 收件人邮箱地址(单个)
     * @param subject 邮件主题
     * @param htmlContent HTML 格式的邮件内容(支持样式、链接、图片等)
     * @throws MessagingException 邮件发送相关异常(如配置错误、网络问题)
     */
    public void sendHtmlMail(String to, String subject, String htmlContent) throws MessagingException {
        sendHtmlMail(new String[]{to}, subject, htmlContent);
    }

    /**
     * 多收件人 HTML 邮件
     * @param to 收件人邮箱地址数组(多个)
     * @param subject 邮件主题
     * @param htmlContent HTML 格式的邮件内容(支持样式、链接、图片等)
     * @throws MessagingException 邮件发送相关异常(如配置错误、网络问题)
     */
    public void sendHtmlMail(String[] to, String subject, String htmlContent) throws MessagingException {
        try {
            // 创建复杂邮件实例(支持 HTML、附件、内嵌图片等)
            MimeMessage message = javaMailSender.createMimeMessage();
            // 创建辅助类,第一个参数:邮件实例;第二个参数:true 表示支持多部分内容(如 HTML);第三个参数:编码格式
            MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
            
            helper.setFrom(defaultFromMail); // 发件人
            helper.setTo(to); // 收件人(多收件人传入数组)
            helper.setSubject(subject); // 邮件主题
            // 第二个参数 true:开启 HTML 解析,否则会将 HTML 标签显示为纯文本
            helper.setText(htmlContent, true);
            
            javaMailSender.send(message); // 发送邮件
            log.info("HTML 邮件发送成功,收件人:{},邮件主题:{}", String.join(",", to), subject);
        } catch (MessagingException e) {
            log.error("HTML 邮件发送失败,收件人:{},邮件主题:{},异常信息:{}", 
                    String.join(",", to), subject, e.getMessage(), e);
            // 抛出异常,由调用方处理(如返回错误信息、重试)
            throw e;
        }
    }
}

2. 测试接口 Controller

提供 REST 接口,可通过 Postman、浏览器直接调用测试,覆盖单收件人、多收件人、文本邮件、HTML 邮件等核心场景;接口参数清晰,注释详细,实际项目中可直接复用,或根据业务需求修改。

go 复制代码
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.mail.MessagingException;

/**
 * 邮件发送测试接口(实际项目中可整合到 Service 层,结合业务场景调用)
 * 接口采用 GET 请求,方便快速测试;正式环境可根据需求改为 POST 请求
 */
@RestController
@RequestMapping("/mail") // 接口统一前缀,便于管理
@RequiredArgsConstructor
public class MailController {

    // 注入邮件工具类,直接调用发送方法
    private final MailUtil mailUtil;

    // 测试:发送纯文本邮件(单收件人,GET请求,方便快速测试)
    @GetMapping("/send/text")
    public String sendTextMail(
            @RequestParam String to, // 收件人邮箱地址(必填)
            @RequestParam String subject, // 邮件主题(必填)
            @RequestParam String content // 邮件纯文本内容(必填)
    ) {
        mailUtil.sendTextMail(to, subject, content);
        return "纯文本邮件发送成功!";
    }

    // 测试:发送 HTML 富文本邮件(单收件人,GET请求,方便快速测试)
    @GetMapping("/send/html")
    public String sendHtmlMail(
            @RequestParam String to, // 收件人邮箱地址(必填)
            @RequestParam String subject // 邮件主题(必填)
    ) throws MessagingException {
        // 构建 HTML 内容(支持样式、链接、表格等,可根据实际业务需求修改)
        // 示例:模拟用户注册验证邮件,包含验证码、链接等核心元素
        String htmlContent = "<!DOCTYPE html>" +
                "<html lang='zh-CN'>" +
                "<head><meta charset='UTF-8'><title>" + subject + "</title></head>" +
                "<body style='font-family: \"Microsoft YaHei\", sans-serif;'>" +
                "<div style='width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #eee; border-radius: 5px;'>" +
                "<h2 style='color: #1E90FF; text-align: center; margin-bottom: 20px;'>用户注册验证</h2>" +
                "<p style='font-size: 14px; line-height: 1.5;'>尊敬的用户,您好!</p>" +
                "<p style='font-size: 14px; line-height: 1.5;'>您正在进行注册验证,本次验证码为:</p>" +
                "<div style='font-size: 24px; color: #FF4500; font-weight: bold; text-align: center; margin: 15px 0;'>123456</div>" +
                "<p style='font-size: 14px; line-height: 1.5;'>验证码有效期为 5 分钟,请在有效期内完成验证。</p>" +
                "<p style='font-size: 14px; line-height: 1.5;'>若您未发起注册操作,请忽略此邮件,感谢您的支持!</p>" +
                "<p style='font-size: 12px; color: #999; margin-transform: translateY( 30px; text-align: center;'>此为系统自动发送邮件,请勿回复</p>" +
                "</div>" +
                "</body></html>";
        mailUtil.sendHtmlMail(to, subject, htmlContent);
        return "HTML 邮件发送成功!";
    }

    // 测试:多收件人发送纯文本邮件(实际场景常用,如批量通知)
    @GetMapping("/send/text/batch")
    public String sendBatchTextMail(
            @RequestParam String[] to, // 多收件人邮箱地址数组(必填,格式:xxx@qq.com,xxx@163.com)
            @RequestParam String subject, // 邮件主题(必填)
            @RequestParam String content // 邮件纯文本内容(必填)
    ) {
        mailUtil.sendTextMail(to, subject, content);
        return "多收件人文本邮件发送成功!共发送 " + to.length + " 个收件人";
    }

    // 测试:多收件人发送 HTML 邮件(实际场景常用,如批量营销、通知)
    @GetMapping("/send/html/batch")
    public String sendBatchHtmlMail(
            @RequestParam String[] to,
            @RequestParam String subject
    ) throws MessagingException {
        // 复用注册验证 HTML 模板,可根据实际需求修改
        String htmlContent = "<!DOCTYPE html>" +
                "<html lang='zh-CN'>" +
                "<body style='font-family: \"Microsoft YaHei\", sans-serif;'>" +
                "<h2 style='color: #1E90FF; text-align: center;'>批量通知邮件</h2>" +
                "<p style='font-size: 14px;'>各位用户,您好!本次批量通知内容如下:</p>" +
                "<p style='font-size: 14px; color: #333;'>系统将于今晚 23:00 进行升级维护,维护期间可能无法正常使用,敬请谅解!</p>" +
                "<p style='font-size: 12px; color: #999; margin-top: 20px;'>此为系统批量发送邮件,请勿回复</p>" +
                "</body></html>";
        mailUtil.sendHtmlMail(to, subject, htmlContent);
        return "多收件人HTML邮件发送成功!共发送 " + to.length + " 个收件人";
    }
}

五、关键注意事项

  • • 授权码是核心,必须填写正确,不可用邮箱登录密码替代,否则邮箱服务器会拒绝发送请求,导致发送失败;若授权码丢失,可重新在邮箱设置中生成。

  • • HTML 邮件必须开启 helper.setText(htmlContent, true),第二个参数为 true 才会解析 HTML 样式,若设为 false,会将 HTML 标签显示为纯文本,失去样式效果。

  • • 测试时优先使用个人邮箱(QQ/163),正式环境建议切换为企业邮箱,因为个人邮箱有发送频率限制(如 QQ 邮箱单日发送上限约 50 封),企业邮箱无明显限制,稳定性更高。

  • • 若邮件发送失败,可开启日志 DEBUG 级别,重点排查以下问题:授权码错误、SMTP 服务器地址错误、端口错误、网络波动、邮箱 SMTP 服务未开启。

  • • 多收件人发送时,直接传入字符串数组 String[] to 即可,无需多次调用发送方法,工具类已做好适配,避免重复创建连接,提升发送效率。

  • • 中文乱码问题:确保配置文件中 default-encoding: UTF-8,同时 MimeMessageHelper 构造方法中指定编码为 UTF-8,即可避免中文乱码。

  • • 异常处理:工具类中已捕获异常并记录日志,实际项目中可根据业务需求添加重试逻辑(如失败后重试 2-3 次),提升邮件发送成功率。

相关推荐
菜菜小狗的学习笔记2 小时前
八股(一)Java基础
java·开发语言
漫霂2 小时前
SpringSecurity入门应用
java·数据库·spring
Anfioo2 小时前
Java 基础-面向对象思想知识点详解
java·开发语言
Seven972 小时前
【从0到1构建一个ClaudeAgent】工具与执行-Agent循环
java
星晨雪海3 小时前
企业标准 DTO 传参 + Controller + Service + 拷贝工具类完整版
java·开发语言·python
devlei9 小时前
从源码泄露看AI Agent未来:深度对比Claude Code原生实现与OpenClaw开源方案
android·前端·后端
pshdhx_albert10 小时前
AI agent实现打字机效果
java·http·ai编程
沉鱼.4410 小时前
第十二届题目
java·前端·算法
努力的小郑11 小时前
Canal 不难,难的是用好:从接入到治理
后端·mysql·性能优化