跳到内容

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: true

Facade 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
配置默认值说明
enabledtrue启用开关
default-providerlog默认 provider
config.enabledtrue数据库配置覆盖开关
config.prefixspring.open.mail后台配置 key 前缀

log / memory provider

配置默认值说明
providers.log.enabledtrue日志 provider 开关
providers.memory.enabledtrue内存 provider 开关
providers.memory.capacity1000内存保留邮件数

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内存保存邮件测试、样板预览
smtpSpring Mail / Jakarta Mail 真实发信生产

扩展点与源码骨架

入口文件说明
自动配置MailAutoConfiguration注册默认 Manager、Facade 绑定器、log / memory / smtp provider 和可选 Config 运行时配置源
业务 FacadeMail业务代码的静态短入口,适合简单发信和获取指定 provider
能力管理器MailManager / DefaultMailManager统一做收件人校验、默认 provider 选择、模板渲染和批量发送
消息载体MailMessage不可变邮件命令对象,承载收件人、标题、正文、模板、变量、附件和 traceId
Provider SPIMailProvider具体投递驱动扩展点,内置 logmemorysmtp
SMTP 投递SmtpMailProvider将已渲染消息转换成 JavaMail MimeMessage,并按运行时配置投递
配置解析MailConfigResolver从本地配置和 ConfigManager 解析 provider 配置,字段 key 由属性 getter 推导为 kebab-case
运行时配置源MailRuntimeConfigSourceMail 与配置中心之间的窄接口,后续可扩展缓存刷新或多租户配置

邮件链路的分层原则:

  • 业务模块只依赖 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: false

Gmail / 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 主机
163smtp.163.com
126smtp.126.com
yeah.netsmtp.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

相关

外部参考:

Released under the Apache License 2.0.