Note 24. SpringBoot3集成SpringMail - 发送您的第一个邮件信息
Note 24. SpringBoot3集成SpringMail - 发送您的第一个邮件信息
Prorise第一章. 邮件服务的核心认知
本章摘要:在动手写代码之前,我们需要先理解"邮件是怎么发出去的"。本章将用最直白的方式讲清楚 SMTP 协议、端口选择、以及前后端分离架构下的邮件设计原则——这些认知将帮助你在后续遇到问题时快速定位原因。
本章学习路径
| 阶段 | 目标 | 解锁能力 |
|---|---|---|
| 1.1 | 理解邮件发送的业务价值 | 能判断何时该用邮件、何时该用短信 |
| 1.2 | 掌握 SMTP 协议与端口选择 | 能解释为什么云服务器连不上 25 端口 |
| 1.3 | 理解前后端分离的邮件架构 | 能说清楚为什么前端不能生成 HTML |
1.1. 为什么你的应用需要发邮件
几乎所有的 Web 应用都绑定了邮件功能。打开你的收件箱看看——注册验证码、密码重置链接、订单发货通知、每周数据报告——这些都是程序自动发出的。
“那为什么不用短信呢?微信通知不是更快吗?”
问得好。我们来做个对比:
| 通知方式 | 单条成本 | 触达率 | 适用场景 |
|---|---|---|---|
| 邮件 | 几乎免费 | 中等(可能进垃圾箱) | 验证码、通知、营销、报表 |
| 短信 | 0.03-0.05 元 | 极高 | 强实时性场景(登录验证) |
| 微信/App 推送 | 免费 | 依赖用户安装 | 已有私域流量的产品 |
结论很清晰:邮件是性价比最高的通知渠道,尤其适合验证码、系统通知这类"必须送达但不紧急"的场景。
1.2. 邮件发送的技术原理
1.2.1. SMTP 协议是什么
SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)是互联网发送邮件的标准协议。
可以把它想象成"邮局的收发室":
- 你的 Spring Boot 应用写好一封信(邮件内容)
- 把信交给收发室(SMTP 服务器,如
smtp.qq.com) - 收发室负责把信投递到收件人的邮箱
我们写代码时,本质上就是在和这个"收发室"对话。
1.2.2. 端口之争:25 vs 465 vs 587
SMTP 服务器监听三个端口,它们的区别是加密方式不同:
| 端口 | 加密方式 | 现状 |
|---|---|---|
| 25 | 无加密(明文) | 几乎所有云服务器都封禁,别想了 |
| 465 | SSL(全程加密) | QQ 邮箱、阿里云企业邮箱的首选 |
| 587 | STARTTLS(先明文再升级加密) | Gmail、国际服务的首选 |
“为什么云服务器要封 25 端口?”
因为 25 端口是垃圾邮件的重灾区。早年黑客租一台云服务器就能疯狂发垃圾邮件,所以阿里云、AWS、腾讯云等厂商一刀切封禁了 25 端口。
记住这个结论:在云服务器上部署时,只能用 465 或 587 端口。
1.2.3. 本节小结
| 概念 | 一句话解释 |
|---|---|
| SMTP | 发邮件的标准协议,相当于"邮局收发室" |
| 端口 465 | SSL 加密通道,国内邮箱首选 |
| 端口 587 | STARTTLS 加密通道,国际邮箱首选 |
| 端口 25 | 已被云厂商封禁,不要使用 |
1.3. 前后端分离架构下的邮件设计哲学
在 Vue + Spring Boot 的分离架构下,一个常见的错误想法是:“既然前端负责页面,那邮件的 HTML 模板也让前端生成,传给后端发送不就行了?”
这是一个严重的安全反模式。
1.3.1. 为什么前端不能生成邮件 HTML
假设我们允许前端传 HTML 给后端发送,恶意用户可以这样攻击:
1 | // 恶意用户篡改请求 |
后端如果直接把这段 HTML 发出去,就成了钓鱼邮件的帮凶。
正确的职责划分:
1 | ┌─────────────┐ JSON 指令 ┌─────────────────┐ API 调用 ┌─────────────┐ |
前端只告诉后端"给这个邮箱发一封注册验证码邮件",具体的 HTML 内容由后端控制。
1.3.2. 两种"去模板化"方案
在前后端分离架构下,后端生成邮件 HTML 有两种主流方式:
方案 A:Java 21 Text Blocks(本地轻量方案)
直接在 Java 代码中用多行字符串拼接 HTML,适合验证码、密码重置等简单邮件。
方案 B:云端 SaaS 模板(企业级方案)
把 HTML 模板托管在 SendGrid、阿里云等服务商后台,后端只传变量 JSON,服务商负责渲染和发送。运营人员改邮件样式无需后端发版。
本教程会依次讲解这两种方案。
1.3.3. 本节小结
| 原则 | 说明 |
|---|---|
| 前端只发指令 | {type: "REGISTER", email: "xx@xx.com"} |
| 后端控制内容 | HTML 由后端生成或由云端模板渲染 |
| 禁止前端传 HTML | 防止 XSS 和钓鱼攻击 |
1.4. 本章总结与核心概念速查
本章建立了邮件服务的基础认知:SMTP 是发邮件的协议,465/587 是可用的加密端口,前后端分离架构下邮件内容必须由后端控制。
速查表:
| 场景 | 推荐方案 |
|---|---|
| 本地开发测试 | QQ 邮箱 SMTP(465 端口) |
| 国际用户产品 | Gmail SMTP 或 SendGrid |
| 国内生产环境 | 阿里云 DirectMail |
| 简单邮件(验证码) | Java 21 Text Blocks |
| 复杂邮件(营销模板) | 云端 SaaS 模板 |
第二章. 本地开发环境搭建
本章摘要:动手时间到!本章将从零开始,用 QQ 邮箱的 SMTP 服务发出第一封邮件。这是所有后续内容的基础——在对接云服务之前,先在本地把流程跑通。
环境版本锁定
| 组件 | 版本 | 说明 |
|---|---|---|
| JDK | 21 | 必须使用 21,我们会用到 Text Blocks 和 Record |
| Spring Boot | 3.3.x | 当前最新稳定版 |
| Maven | 3.9+ | 构建工具 |
| IDE | IntelliJ IDEA 2024.1+ | 社区版即可 |
本章学习路径
| 阶段 | 目标 | 解锁能力 |
|---|---|---|
| 2.1 | 创建项目并引入依赖 | 拥有一个可运行的 Spring Boot 骨架 |
| 2.2 | 配置 QQ 邮箱 SMTP | 能解释 application.yml 中每个参数的作用 |
| 2.3 | 编写邮件发送服务 | 能发送纯文本和 HTML 格式的邮件 |
| 2.4 | 暴露测试接口 | 通过 HTTP 请求触发邮件发送 |
2.1. 项目初始化与依赖引入
2.1.1. 创建 Spring Boot 项目
步骤 1:打开 Spring Initializr
在浏览器中访问 https://start.spring.io/,按以下配置填写:
- Project:Maven
- Language:Java
- Spring Boot:3.3.x(选择最新的 3.3 稳定版)
- Group:
com.example - Artifact:
mail-demo - Packaging:Jar
- Java:21
步骤 2:添加依赖
在右侧 “Dependencies” 区域,点击 “ADD DEPENDENCIES”,搜索并添加:
- Spring Web:提供 REST 接口能力
- Java Mail Sender:邮件发送核心包
步骤 3:生成并导入项目
点击 “GENERATE” 下载压缩包,解压后用 IDEA 打开。等待 Maven 依赖下载完成(观察右下角进度条)。
成功标志:pom.xml 中无红色报错,且包含以下依赖:
1 | <dependencies> |
2.1.2. 本节小结
| 完成项 | 状态 |
|---|---|
| 创建 Spring Boot 3.3 项目 | ✅ |
引入 spring-boot-starter-mail | ✅ |
| Maven 依赖下载成功 | ✅ |
2.2. QQ 邮箱 SMTP 配置实战
在写代码之前,我们需要先获取 QQ 邮箱的"授权码"——这是 SMTP 服务的专用密码,和你的 QQ 登录密码不同。
2.2.1. 获取 QQ 邮箱授权码
步骤 1:登录 QQ 邮箱
在浏览器中打开 https://mail.qq.com/,登录你的 QQ 邮箱。
步骤 2:进入设置页面
点击页面顶部的 “设置” → “账户”。
步骤 3:开启 SMTP 服务
向下滚动找到 “POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV 服务” 区域,点击 “IMAP/SMTP服务” 右侧的 “开启”。
步骤 4:验证并获取授权码
按提示用密保手机发送短信验证。验证成功后,页面会显示一个 16 位授权码(类似 abcdefghijklmnop)。
重要:这个授权码只显示一次!请立即复制保存。如果忘记了,需要重新生成。
成功标志:你手上有一个 16 位的授权码字符串。
2.2.2. 编写 application.yml 配置
在 src/main/resources/ 目录下,将 application.properties 重命名为 application.yml(YAML 格式更易读),然后填入以下内容:
1 | spring: |
配置项解读:
| 配置项 | 作用 | 不配会怎样 |
|---|---|---|
host | 指定 SMTP 服务器地址 | 连接失败,不知道往哪发 |
port | 指定端口号 | 默认 25,但会被云服务器封禁 |
username | SMTP 认证账号 | 535 认证失败 |
password | SMTP 认证密码(授权码) | 535 认证失败 |
ssl.enable | 开启 SSL 加密 | 465 端口连接超时 |
2.2.3. 本节小结
| 完成项 | 状态 |
|---|---|
| 获取 QQ 邮箱授权码 | ✅ |
配置 application.yml | ✅ |
| 理解每个配置项的作用 | ✅ |
2.3. 编写邮件发送服务
配置完成后,我们来编写核心的邮件发送逻辑。
2.3.1. 创建项目目录结构
在 src/main/java/com/example/maildemo/ 下创建以下包结构:
1 | src/main/java/com/example/maildemo/ |
2.3.2. 编写 EmailService
我们先实现两个方法:发送纯文本邮件和发送 HTML 邮件。
📄 文件:src/main/java/com/example/maildemo/service/EmailService.java
1 | package com.example.maildemo.service; |
代码要点解读:
SimpleMailMessagevsMimeMessage:前者只能发纯文本,后者支持 HTML 和附件FROM_EMAIL必须一致:发件人地址必须和application.yml中的username完全相同,否则会报 553 错误- Text Blocks:Java 21 的多行字符串语法,用
"""包裹,.formatted()填充变量
2.3.3. 本节小结
| 完成项 | 状态 |
|---|---|
创建 EmailService 类 | ✅ |
| 实现纯文本邮件发送 | ✅ |
| 实现 HTML 邮件发送 | ✅ |
| 使用 Text Blocks 构建验证码模板 | ✅ |
2.4. 编写测试接口验证成果
最后一步:暴露一个 HTTP 接口,让我们能通过浏览器或 Postman 触发邮件发送。
2.4.1. 创建请求 DTO
📄 文件:src/main/java/com/example/maildemo/controller/EmailRequest.java
1 | package com.example.maildemo.controller; |
2.4.2. 创建 EmailController
📄 文件:src/main/java/com/example/maildemo/controller/EmailController.java
1 | package com.example.maildemo.controller; |
2.4.3. 启动项目并测试
步骤 1:启动应用
在 IDEA 中运行 MailDemoApplication 的 main 方法。
成功标志:控制台输出 Started MailDemoApplication in x.xxx seconds,无报错。
步骤 2:发送测试请求
使用 IDEA 自带的 HTTP Client(或 Postman),发送以下请求:
1 | POST http://localhost:8080/api/email/send-code |
成功标志:
- 接口返回
{"message": "验证码已发送"} - 收件箱收到一封带有验证码的 HTML 邮件
2.4.4. 本节小结
| 完成项 | 状态 |
|---|---|
创建 EmailController | ✅ |
暴露 /api/email/send-code 接口 | ✅ |
| 成功发送并收到测试邮件 | ✅ |
2.5. 本章总结与本地方案速查
本章完成了从零到一的本地邮件发送功能。我们使用 QQ 邮箱的 SMTP 服务,通过 JavaMailSender 发送了纯文本和 HTML 格式的邮件。
遇到以下场景时,直接 Copy 下方代码:
场景 1:发送纯文本通知
需求:发送一封简单的文字通知邮件
1 |
|
场景 2:发送 HTML 验证码邮件
需求:发送带样式的验证码邮件
1 | public void sendCode(String to, String code) { |








