Mail Starter
受众:开发者 摘要:统一邮件 Facade。log / memory / smtp 三种 provider,模板渲染,数据库配置覆盖,QQ / Gmail / 网易常见服务商配置。
何时使用
| 场景 | 建议 |
|---|---|
| 简单文本邮件 | Mail.send(to, subject, content) |
| HTML 邮件 | MailMessage.builder().html(true).content("<h1>...</h1>") |
| 模板邮件(接入 Template starter) | MailMessage.builder().template("mail.welcome").variable("...", ...) |
| 通过 Notification 多通道(站内信 + 邮件 + 短信) | 用 notification.md mail 通道 |
| 本地开发不真发邮件 | 默认 log provider,只记录日志 |
| 单元测试 | memory provider |
| 生产真发邮件 | smtp provider |
业务代码只依赖 Mail Facade / MailManager / MailProvider,不直接绑定 SMTP / JavaMail / 具体邮箱服务商。
快速开始
默认 log provider 本地不发邮件,只记录日志:
java
Mail.send("user@example.com", "欢迎使用", "你的账号已经创建成功");启用真实发信切到 smtp:
yaml
spring:
open:
mail:
default-provider: smtp
providers:
smtp:
enabled: true
provider: smtp
host: smtp.qq.com
port: 465
username: ${MAIL_USERNAME:your@qq.com}
password: ${MAIL_PASSWORD:} # QQ 用授权码
from: ${MAIL_FROM:your@qq.com}
from-name: 系统通知
ssl-enabled: trueFacade API
java
// 简单文本
Mail.send(to, subject, content);
// 完整消息(HTML / 附件 / 抄送 / 模板等)
Mail.send(MailMessage.builder()
.to(MailAddress.of("user@example.com"))
.cc(MailAddress.of("cc@example.com"))
.subject("订单已支付")
.content("<h1>支付成功</h1><p>感谢你的购买。</p>")
.html(true)
.build());
// 模板邮件
Mail.send(MailMessage.builder()
.to(MailAddress.of("user@example.com"))
.template("mail.welcome")
.variable("username", "Alice")
.build());配置项
通用
yaml
spring:
open:
mail:
enabled: true
default-provider: log # log / memory / smtp
config:
enabled: true # 允许数据库配置覆盖
prefix: spring.open.mail| 配置 | 默认值 | 说明 |
|---|---|---|
enabled | true | 启用开关 |
default-provider | log | 默认 provider |
config.enabled | true | 数据库配置覆盖开关 |
config.prefix | spring.open.mail | 后台配置 key 前缀 |
log / memory provider
| 配置 | 默认值 | 说明 |
|---|---|---|
providers.log.enabled | true | 日志 provider 开关 |
providers.memory.enabled | true | 内存 provider 开关 |
providers.memory.capacity | 1000 | 内存保留邮件数 |
smtp provider
yaml
spring:
open:
mail:
providers:
smtp:
enabled: false
provider: smtp
host: "" # SMTP 主机
port: 587 # 587(STARTTLS)/ 465(SSL)
protocol: smtp
username: "" # 完整邮箱地址
password: "" # 授权码 / 应用专用密码
from: "" # 默认发件人邮箱
from-name: "" # 默认发件人显示名
default-encoding: UTF-8
auth: true
starttls-enabled: true # 587 端口启用
ssl-enabled: false # 465 端口启用
debug: false
connection-timeout: 10s
timeout: 10s
write-timeout: 10s配置优先级:数据库配置同名 key > 环境变量 / .env > application.yml 默认值。
Provider
| Provider | 说明 | 适用 |
|---|---|---|
log | 只输出日志,不真发 | 默认,本地开发 |
memory | 内存保存邮件 | 测试、样板预览 |
smtp | Spring Mail / Jakarta Mail 真实发信 | 生产 |
扩展点与源码骨架
| 入口 | 文件 | 说明 |
|---|---|---|
| 自动配置 | MailAutoConfiguration | 注册默认 Manager、Facade 绑定器、log / memory / smtp provider 和可选 Config 运行时配置源 |
| 业务 Facade | Mail | 业务代码的静态短入口,适合简单发信和获取指定 provider |
| 能力管理器 | MailManager / DefaultMailManager | 统一做收件人校验、默认 provider 选择、模板渲染和批量发送 |
| 消息载体 | MailMessage | 不可变邮件命令对象,承载收件人、标题、正文、模板、变量、附件和 traceId |
| Provider SPI | MailProvider | 具体投递驱动扩展点,内置 log、memory、smtp |
| SMTP 投递 | SmtpMailProvider | 将已渲染消息转换成 JavaMail MimeMessage,并按运行时配置投递 |
| 配置解析 | MailConfigResolver | 从本地配置和 ConfigManager 解析 provider 配置,字段 key 由属性 getter 推导为 kebab-case |
| 运行时配置源 | MailRuntimeConfigSource | Mail 与配置中心之间的窄接口,后续可扩展缓存刷新或多租户配置 |
邮件链路的分层原则:
- 业务模块只依赖
Mail/MailManager/MailMessage,不直接依赖 JavaMail。 DefaultMailManager处理模板渲染和 provider 选择,provider 只处理具体投递。MailConfigResolver每次 SMTP 投递前读取当前配置,后台修改同名配置后下一次发送即可生效。MailAutoConfiguration默认启用log/memory,SMTP 只有显式启用才注册,避免开发环境误发真实邮件。- 新增 provider 时优先实现
MailProvider,再在自动配置中按条件注册 Bean;不要把第三方 SDK 细节泄露到业务接口。
常见服务商配置
QQ 邮箱
QQ 邮箱用授权码作为 SMTP 密码(不是登录密码):
yaml
spring:
open:
mail:
default-provider: smtp
providers:
smtp:
enabled: true
host: smtp.qq.com
port: 465 # 或 587 + starttls-enabled: true
username: ${MAIL_USERNAME:your@qq.com}
password: ${MAIL_PASSWORD:}
from: ${MAIL_FROM:your@qq.com}
from-name: 系统通知
ssl-enabled: true
starttls-enabled: falseGmail / Google Workspace
Google Workspace 建议优先用 SMTP relay;Gmail SMTP 用 smtp.gmail.com,SSL 用 465,TLS 用 587,密码用应用专用密码:
yaml
spring:
open:
mail:
providers:
smtp:
host: smtp.gmail.com
port: 587 # 或 465 + ssl-enabled: true
username: your@gmail.com
password: ${MAIL_PASSWORD:}
from: your@gmail.com
starttls-enabled: true
ssl-enabled: false生产环境建议用企业域名邮箱、SMTP relay 或专业邮件服务商,并配置 SPF / DKIM / DMARC。
网易邮箱
| 邮箱 | SMTP 主机 |
|---|---|
| 163 | smtp.163.com |
| 126 | smtp.126.com |
| yeah.net | smtp.yeah.net |
yaml
spring:
open:
mail:
providers:
smtp:
host: smtp.163.com # 改成对应域名
port: 465
username: your@163.com
password: ${MAIL_PASSWORD:} # 授权码
ssl-enabled: true
starttls-enabled: false网易需要先在邮箱后台开启 SMTP / 客户端授权。
模板邮件
接入 Template starter(存在 TemplateManager Bean 时自动启用):
java
Mail.send(MailMessage.builder()
.to(MailAddress.of("user@example.com"))
.template("mail.welcome") // 模板编码
.variable("username", "Alice") // 模板变量
.locale(Locale.SIMPLIFIED_CHINESE) // 可选
.build());模板内容统一在 Template 核心模块的 /api/v1/admin/template/templates 后台维护。
通过 Notification 发送
Notification mail 通道委托 Mail starter:
java
Notification.send("mail", NotificationMessage.builder()
.subject("任务完成")
.content("你的导出任务已经完成。")
.recipient(NotificationRecipient.email("user@example.com"))
.build());启用通道:
yaml
spring:
open:
notification:
channels:
mail:
enabled: true后台配置
生产环境密钥放数据库配置或环境变量,不写入代码仓库:
text
spring.open.mail.default-provider=smtp
spring.open.mail.providers.smtp.enabled=true
spring.open.mail.providers.smtp.host=smtp.qq.com
spring.open.mail.providers.smtp.port=465
spring.open.mail.providers.smtp.username=your@qq.com
spring.open.mail.providers.smtp.password=<授权码>
spring.open.mail.providers.smtp.from=your@qq.com
spring.open.mail.providers.smtp.ssl-enabled=true
spring.open.mail.providers.smtp.starttls-enabled=false环境变量:
dotenv
SPRING_OPEN_MAIL_DEFAULT_PROVIDER=smtp
SPRING_OPEN_MAIL_PROVIDERS_SMTP_ENABLED=true
SPRING_OPEN_MAIL_PROVIDERS_SMTP_HOST=smtp.qq.com
SPRING_OPEN_MAIL_PROVIDERS_SMTP_USERNAME=your@qq.com
SPRING_OPEN_MAIL_PROVIDERS_SMTP_PASSWORD=<授权码>
SPRING_OPEN_MAIL_PROVIDERS_SMTP_SSL_ENABLED=true排查
| 现象 | 排查 |
|---|---|
mail.smtp.host-required | 启用了 smtp provider 但没配置 host |
| 认证失败 | 检查是否使用授权码或应用专用密码(不是邮箱登录密码) |
| 连接失败 | 端口和加密方式匹配?465 → SSL,587 → STARTTLS |
| 被拒收或进垃圾箱 | 检查发件域名的 SPF / DKIM / DMARC DNS 配置 |
| 本地调试 | 先用 log / memory provider,确认链路无误后切 smtp |
注意事项
- 日志 provider 不输出完整邮箱、密码、授权码、token、secret
- 生产环境密钥必须走数据库配置或环境变量
- 不在低延迟链路(订单 / 支付)同步发邮件,建议异步 + 重试
- 模板邮件的变量名保持 i18n key 风格
验证命令
bash
./mvnw -pl spring-open-starters/spring-open-starter-mail -am test -DskipITs相关
- 通知(多通道):notification.md
- 模板:template.md
- 配置中心(数据库配置):config.md
- Provider 扩展模型:provider.md
外部参考: