在现代的 Web 应用开发中,邮件功能几乎是不可或缺的一环。无论是用户注册验证、密码找回、系统通知,还是营销推广,都需要通过邮件与用户建立联系。本文将带你从零开始,使用 Spring Boot 和 Jakarta Mail 实现一个稳定、可配置的邮件发送功能。

我们将基于一个实际的 Spring Boot 项目案例,详细讲解如何集成邮件服务,并提供完整的代码示例和配置说明。

前期准备:

在邮箱设置中开启SMTP服务并获取授权码


📦 1. 项目依赖:引入 Jakarta Mail

首先,在 pom.xml 中添加邮件支持的依赖。从 Java EE 迁移到 Jakarta EE 后,推荐使用 jakarta.mail 替代旧的 javax.mail

<dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>jakarta.mail</artifactId>
    <version>2.0.1</version>
</dependency>

✅ 提示:jakarta.mailjavax.mail 的继任者,适用于 Jakarta EE 9+ 和 Spring Boot 3+ 环境。


🛠️ 2. 邮件配置:使用 application.yml

为了实现配置与代码分离,我们将邮件服务器的相关信息写入 application.yml

mail:
  host: smtp.qiye.163.com     # 邮箱服务器地址(SMTP)
  port: 587                   # SMTP 端口(启用 STARTTLS)
  username: hash@ithash.cn    # 发件人邮箱账号
  password: xxxxxxxxxxxx   # 客户端授权码(非登录密码!)

⚠️ 安全提醒:password 应填写邮箱的 客户端授权码,而不是登录密码。以网易企业邮箱为例,需在邮箱设置中开启“客户端授权密码”功能并生成专用密钥。

常用邮箱的SMTP服务器地址和端口信息汇总表:

邮箱服务商

SMTP服务器地址

常用端口(TLS/STARTTLS)

常用端口(SSL)

备注

Gmail

smtp.gmail.com

587

465

需开启“两步验证”并使用“应用专用密码”

Yahoo Mail

smtp.mail.yahoo.com

587

465

需在账户设置中开启“应用密码”

Outlook / Hotmail

smtp-mail.outlook.com

587

-

不支持SSL端口,仅使用TLS

QQ邮箱

smtp.qq.com

587

465

需在设置中开启SMTP服务并生成“授权码”

163邮箱

smtp.163.com

25 / 587

994

推荐使用465或994加密端口

126邮箱

smtp.126.com

25 / 587

994

推荐使用465或994加密端口

网易企业邮箱

smtp.qiye.163.com

587

994

注意:imap.qiye.163.com 是IMAP/POP3地址,SMTP应使用 smtp.qiye.163.com


📌 重要提示:

  1. 授权码 vs 登录密码
    对于QQ、网易系列(163/126/企业邮)等国内邮箱,不能直接使用登录密码进行SMTP验证。必须在邮箱设置中开启“SMTP服务”,并生成一个客户端授权码用于程序登录。

  2. TLS 与 SSL 端口区别

    • 端口 587 + STARTTLS/TLS:明文连接后升级为加密(推荐)

    • 端口 465 / 994 + SSL:直接建立SSL加密连接(传统方式)

  3. 安全性建议

    • 优先使用 TLS(端口587)或 SSL(如465/994)进行加密传输。

    • 不要将密码或授权码硬编码在代码中,应使用配置文件或环境变量管理。


🧩 3. 配置类:封装邮件参数

我们创建一个配置类 EmailSenderPropertis,用于自动绑定 application.yml 中的配置项。

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import lombok.Data;

@Data
@Component
@ConfigurationProperties(prefix = "mail")
public class EmailSenderPropertis {
    private String host;
    private String port;
    private String username;
    private String password;
}
  • @ConfigurationProperties(prefix = "mail"):将 mail.* 配置自动映射到该类字段。

  • @Data:Lombok 注解,自动生成 getter/setter、toString 等方法。

  • @Component:注册为 Spring 容器的 Bean。


📨 4. 邮件发送核心类:EmailSender

这是整个功能的核心,负责构建邮件并发送。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import jakarta.mail.*;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import java.util.Properties;

@Component
public class EmailSender {

    @Autowired
    private EmailSenderPropertis emailSenderPropertis;

    /**
     * 发送简单文本邮件
     * @param to 接收方邮箱
     * @param subject 邮件主题
     * @param body 邮件正文
     */
    public void send(String to, String subject, String body) {
        String host = emailSenderPropertis.getHost();
        String port = emailSenderPropertis.getPort();
        String username = emailSenderPropertis.getUsername();
        String password = emailSenderPropertis.getPassword();

        // 1. 设置邮件服务器属性
        Properties props = new Properties();
        props.put("mail.smtp.host", host);
        props.put("mail.smtp.port", port);
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.starttls.enable", "true"); // 启用 TLS 加密

        // 2. 创建身份认证器
        Authenticator auth = new Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password);
            }
        };

        // 3. 获取邮件会话
        Session session = Session.getInstance(props, auth);

        try {
            // 4. 构建邮件内容
            Message message = new MimeMessage(session);
            message.setFrom(new InternetAddress(username)); // 发件人
            message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to)); // 收件人
            message.setSubject(subject); // 主题
            message.setText(body); // 正文(纯文本)

            // 5. 发送邮件
            Transport.send(message);
            System.out.println("✅ 邮件发送成功!");

        } catch (MessagingException e) {
            e.printStackTrace();
            System.err.println("❌ 发送邮件失败: " + e.getMessage());
        }
    }
}

🔍 关键点解析:

步骤

说明

1. Properties 设置

指定 SMTP 服务器地址、端口、启用认证和 TLS 加密

2. Authenticator

匿名内部类实现身份验证,传入用户名和授权码

3. Session

表示与邮件服务器的会话,是发送邮件的前提

4. MimeMessage

构建标准的 MIME 邮件格式

5. Transport.send()

静态方法,直接发送邮件


✅ 5. 测试验证:使用 JUnit 单元测试

编写测试类验证邮件是否能正常发送。

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class EmailTest {

    @Autowired
    private EmailSender emailSender;

    @Test
    public void testSend() {
        emailSender.send("x@ithash.cn", "测试邮件", "这是一封测试邮件");
    }
}

注意在测试类上使用 @SpringBootTest 注解。该注解用于启动完整的 Spring 应用上下文,以便在测试中能够正确地注入和使用 Spring Bean(如 EmailSender)以及加载Sping配置文件。这将确保你的单元测试能够在与实际应用相同的环境中运行,从而提高测试的准确性和可靠性。

运行测试后,如果控制台输出 ✅ 邮件发送成功!,并且收件箱收到邮件,则说明集成成功。


🛡️ 6. 常见问题与解决方案

❌ 发送失败:Could not connect to SMTP host

  • 检查 hostport 是否正确。

  • 确保网络可访问该 SMTP 服务器(可能被防火墙拦截)。

  • 企业邮箱可能需要开启 SMTP 服务。

❌ 认证失败:Authentication failed

  • 注意网易邮箱网易企业邮箱的SMTP服务器地址不同。

  • 确认 password授权码 而非登录密码。

  • 检查用户名是否完整(包含域名,如 xxx@ithash.cn)。

❌ TLS/SSL 问题

  • 若使用端口 465,应使用 mail.smtp.ssl.enable=true 并关闭 starttls

  • 端口 587 通常配合 STARTTLS 使用(本文配置)。


🚀 7. 扩展功能建议

  1. 发送 HTML 网页邮件
    使用 message.setContent(body, "text/html;charset=UTF-8") 替代 setText()

  2. 添加附件
    使用 MimeMultipart 构建多部分消息。

  3. 异步发送
    使用 @Async 注解提升系统响应速度。

  4. 模板引擎集成
    结合 Thymeleaf 或 FreeMarker 生成动态邮件内容。

  5. 日志与监控
    记录发送状态,集成邮件发送成功率监控。


📚 8. 总结

本文通过一个完整的 Spring Boot 示例,演示了如何使用 Jakarta Mail 实现邮件发送功能。我们实现了:

  • 配置与代码解耦

  • 安全的授权码机制

  • 可复用的邮件发送组件

  • 单元测试验证

这套方案简洁、稳定,适用于大多数企业级应用。你可以在此基础上扩展更复杂的邮件功能,如批量发送、定时任务、失败重试等。