一、前言

在实际项目开发中,邮件发送是非常常见的功能,例如用户注册验证码、登录验证、消息通知、异常告警等场景都需要用到邮件服务。

Spring Boot 提供了开箱即用的 spring-boot-starter-mail 依赖,可以非常方便地实现邮件发送功能。本文将详细讲解单体应用中快速集成邮件发送,以及微服务架构下将邮件能力封装为公共 starter 模块,供其他业务服务复用的完整实现方案。

二、基础环境准备

1. 引入 Spring Boot Mail Starter 依赖

在需要使用邮件功能的服务 pom.xml 中引入邮件启动器依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

2. 获取 QQ 邮箱 SMTP 授权码

以 QQ 邮箱为例,获取 SMTP 授权码步骤:

  1. 登录网页版 QQ 邮箱
  2. 进入 设置 → 账号与安全 → 安全设置
  3. 开启 POP3/IMAP/SMTP 服务
  4. 点击 生成授权码,完成安全验证后即可获得一串授权码
  5. 该授权码即为配置文件中 password 对应的值,不是邮箱登录密码
    在这里插入图片描述

三、单体服务下邮件发送实现

1. 编写邮件配置文件

application.yml 中添加邮件相关配置:

spring:
  mail:
    # 邮箱 SMTP 地址
    host: smtp.qq.com  # QQ 邮箱
    #host: smtp.163.com # 163 邮箱
    #host: smtp.exmail.qq.com # 腾讯企业邮箱

    username: 你的发件邮箱地址
    password: 刚才生成的 SMTP 授权码

    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
            required: true
    default-encoding: UTF-8

2. 开发 EmailUtil 邮件工具类

单体应用中直接使用 @Component 将工具类交给 Spring 管理:

import jakarta.annotation.Resource;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class EmailUtil {

    @Resource
    private JavaMailSender javaMailSender;

    @Resource
    private MailProperties mailProperties;

    public EmailUtil(JavaMailSender javaMailSender, MailProperties mailProperties) {
        this.javaMailSender = javaMailSender;
        this.mailProperties = mailProperties;
    }

    /**
     * 发送邮箱验证码
     *
     * @param toEmail 收件人
     * @param code    验证码
     * @throws MessagingException
     */
    public void sendEmailCode(String toEmail, String code) throws MessagingException {
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);

        helper.setFrom(mailProperties.getUsername());
        helper.setTo(toEmail);
        helper.setSubject("登录验证码");

        String content = "<h3>你的验证码是:" + code + "</h3>"
                + "<p>5分钟内有效,请勿泄露给他人</p>";

        helper.setText(content, true);
        javaMailSender.send(message);
        log.info("发送验证码到邮箱成功,邮箱:{},验证码:{}", toEmail, code);
    }

    /**
     * 通用邮件发送
     *
     * @param toEmail 收件人
     * @param subject 邮件主题
     * @param content 邮件内容
     * @throws MessagingException
     */
    public void sendEmailCode(String toEmail, String subject, String content) throws MessagingException {
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);

        helper.setFrom(mailProperties.getUsername());
        helper.setTo(toEmail);
        helper.setSubject(subject);

        helper.setText(content, true);
        javaMailSender.send(message);
        log.info("发送邮件到邮箱成功,邮箱:{},主题:{}, 内容:{}", toEmail, subject, content);
    }
}

3. 注入使用 EmailUtil

在业务 Service/Controller 中直接注入使用:

@Resource
private EmailUtil emailUtil;

// 发送验证码
emailUtil.sendEmailCode("xxx@qq.com", "123456");

四、微服务场景下公共邮件模块封装

微服务项目中,通常会将邮件发送抽成公共模块,避免每个服务重复编写代码,此时不能使用 @Component 直接注入,需要通过 Spring Boot 自动装配实现。

1. 改造 EmailUtil 工具类

移除 @Component,@Resource 注解,仅保留构造器注入:

import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;

@Slf4j
public class EmailUtil {

    private final JavaMailSender javaMailSender;
    private final MailProperties mailProperties;

    public EmailUtil(JavaMailSender javaMailSender, MailProperties mailProperties) {
        this.javaMailSender = javaMailSender;
        this.mailProperties = mailProperties;
    }

    /**
     * 发送邮箱验证码
     */
    public void sendEmailCode(String toEmail, String code) throws MessagingException {
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);

        helper.setFrom(mailProperties.getUsername());
        helper.setTo(toEmail);
        helper.setSubject("登录验证码");

        String content = "<h3>你的验证码是:" + code + "</h3>"
                + "<p>5分钟内有效,请勿泄露给他人</p>";

        helper.setText(content, true);
        javaMailSender.send(message);
        log.info("发送验证码到邮箱成功,邮箱:{},验证码:{}", toEmail, code);
    }

    /**
     * 通用邮件发送
     */
    public void sendEmailCode(String toEmail, String subject, String content) throws MessagingException {
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);

        helper.setFrom(mailProperties.getUsername());
        helper.setTo(toEmail);
        helper.setSubject(subject);

        helper.setText(content, true);
        javaMailSender.send(message);
        log.info("发送邮件到邮箱成功,邮箱:{},主题:{}, 内容:{}", toEmail, subject, content);
    }
}

2. 编写自动配置类

创建自动配置类,将 EmailUtil 注册为 Spring Bean:

import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.javamail.JavaMailSender;

@Configuration
public class EmailAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean // 先去 Spring 容器里找一找,没有再进行创建
    public EmailUtil emailUtil(JavaMailSender javaMailSender, MailProperties mailProperties) {
        return new EmailUtil(javaMailSender, mailProperties);
    }
}

作用:

  • EmailUtil 注入 Spring 容器
  • 自动注入 JavaMailSenderMailProperties 完成初始化
  • @ConditionalOnMissingBean 保证业务侧可自定义覆盖

3. 实现 Spring Boot 自动装配

在公共模块的资源目录下创建文件:

resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

文件中写入配置类全限定名:

com.xxx.common.mail.config.EmailAutoConfiguration

Spring Boot 启动时会自动加载该配置类。
在这里插入图片描述
在这里插入图片描述

4. 业务服务引入公共模块并配置

  1. 业务服务 pom.xml 引入公共邮件模块
  2. 业务服务配置文件中依旧配置 spring.mail 相关信息(与单体应用一致)
  3. 直接注入 EmailUtil 即可使用

五、邮件发送使用示例

@RestController
@RequestMapping("/mail")
@RequiredArgsConstructor
public class MailController {

    private final EmailUtil emailUtil;

    @GetMapping("/send/code")
    public String sendCode(String email) throws MessagingException {
        // 生成6位数字验证码
        String code = String.valueOf((int)((Math.random() * 9 + 1) * 100000));
        emailUtil.sendEmailCode(email, code);
        return "发送成功";
    }

    @GetMapping("/send/custom")
    public String sendCustom(String email, String subject, String content) throws MessagingException {
        emailUtil.sendEmailCode(email, subject, content);
        return "发送成功";
    }
}

六、常见问题与注意事项

  1. password 不是邮箱密码,是 SMTP 授权码
  2. 发送失败检查:SMTP 地址、端口、授权码、网络策略、防火墙
  3. 微服务公共模块必须配置自动装配文件,否则无法注入
  4. 建议对邮件发送做异常捕获、重试机制、限流防刷
  5. 验证码建议存入 Redis 并设置过期时间(如 5 分钟)
  6. 避免频繁发送导致邮箱被判定为垃圾邮件
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐