配置邮件(SMTP)
On-Premises 控制面可以通过你自行运维或订阅的 SMTP 中继发送邮件。只有 cp-api 会发送邮件,它使用中继发送三类邮件:
- 邀请邮件。 管理员邀请成员时,邀请链接会通过邮件发给受邀人。参见邀请成员。
- 密码重置邮件。 忘记密码的用户可以在登录页申请重置链接。参见重置忘记的密码。
- 设置密码邮件。 管理员为成员启用登录或重置成员密码时,一次性链接会通过邮件发给该成员。参见启用登录或重置密码。
在设置中继主机之前,邮件功能处于关闭状态。此时,控制台会显示每条邀请链接和设置密码链接,由管理员手动转交;忘记密码页面会提示用户联系管理员。
设置
使用 Helm 配置值配置中继;Docker Compose 安装则在 ./aisix-self-hosted/.env 中配置:
| Helm 配置项 | Docker Compose 变量 | 作用 |
|---|---|---|
api.smtp.host | AISIX_CLOUD_SMTP_HOST | 中继主机名。默认留空,表示关闭邮件功能。 |
api.smtp.tls | AISIX_CLOUD_SMTP_TLS | 连接的保护方式:starttls(默认)、smtps 或 none。参见连接安全。 |
api.smtp.port | AISIX_CLOUD_SMTP_PORT | 中继端口。未设置时按 TLS 模式取值:starttls 为 587,smtps 为 465,none 为 25。 |
api.smtp.from | AISIX_CLOUD_SMTP_FROM | 所有邮件的发件人地址,例如 AISIX <noreply@example.com>。设置了主机时必填。 |
api.smtp.username | AISIX_CLOUD_SMTP_USERNAME | SMTP 身份认证的用户名。可选,参见身份认证。 |
api.smtp.password,或 api.smtp.existingSecret 与 api.smtp.existingSecretKey | AISIX_CLOUD_SMTP_PASSWORD | SMTP 身份认证的密码。Chart 会把 api.smtp.password 存放在自己的 Secret 中,或者从已有 Secret 中读取 api.smtp.existingSecretKey 指定的键(默认为 smtp-password)。 |
api.smtp.invitationLimitPerHour | AISIX_CLOUD_SMTP_INVITATION_LIMIT_PER_HOUR | 单个账号每个滚 动小时最多可发送的邀请邮件数。默认为 50。参见邀请邮件数量限制。 |
在 cp-api 配置文件中,这些设置属于 smtp 组:smtp.host、smtp.port、smtp.tls、smtp.from、smtp.username 和 smtp.invitation_limit_per_hour。密码永远不会从配置文件读取,只能通过 AISIX_CLOUD_SMTP_PASSWORD 环境变量传给 cp-api,Chart 会从 Secret 填充该变量。
设置了主机时,如果出现以下任一情况,cp-api 会在启动时拒绝启动,并指出有问题的设置:
from缺失,或不是有效的邮箱地址;- 用户名和密码只设置了其中一个;
- TLS 模式不是
starttls、smtps或none之一;或 - 端口不在
1–65535范围内。
即使邮件功能处于关闭状态,如果端口不是数字,或邀请邮件数量限制不是不小于 1 的整数,cp-api 同样会拒绝启动。
因此,配置错误的中继会让控制面在启动时就停止,而不是等到第一封邀请邮件才失败。
Helm
如果中继需要身份认证,请将密码保存在你自己管理的 Secret 中:
kubectl create secret generic aisix-smtp \
--namespace aisix-cp --from-literal=smtp-password='YOUR_SMTP_PASSWORD'
api:
smtp:
host: smtp.example.com
from: "AISIX <noreply@example.com>"
username: aisix-notifications
existingSecret: aisix-smtp
使用 helm upgrade 应用这些配置值。修改 api.smtp 配置值会滚动更新 cp-api Pod。
Docker Compose
在 ./aisix-self-hosted/.env 中添加以下设置:
AISIX_CLOUD_SMTP_HOST=smtp.example.com
AISIX_CLOUD_SMTP_FROM="AISIX <noreply@example.com>"
AISIX_CLOUD_SMTP_USERNAME=aisix-notifications
AISIX_CLOUD_SMTP_PASSWORD=YOUR_SMTP_PASSWORD
然后在 ./aisix-self-hosted 目录中重建 cp-api:
docker compose up -d api
身份认证
同时设置用户名和密码,即可向中继进行身份认证。cp-api 会使用 PLAIN 机制;如果中继只提供 LOGIN,则使用 LOGIN。
两者都留空即可不认证直接发送,例如通过一个按 IP 地址放行控制面的内部中继发送。此时即使中继声明支持身份认证,cp-api 也不会进行认证:
api:
smtp:
host: mail-relay.internal.example.com
from: "AISIX <noreply@example.com>"
只设置其中一个会在启动时被拒绝。
连接安全
| 模式 | 行为 |
|---|---|
starttls | 先以明文连接,再通过 STARTTLS 升级连接。如果中继不提供 STARTTLS,投递会失败,而不会继续以明文发送。 |
smtps | 从第一个字节起就使用 TLS,通常使用端口 465。 |
none | 从不加密连接,也不会尝试 STARTTLS。 |
在 starttls 和 smtps 模式下,cp-api 始终使用 cp-api 镜像的系统信任库校验中继证书。没有跳过校验或指定自定义 CA 的设置。
使用 none 时,每封邮件都以明文在网络中传输,包括其中的邀请链接和密码重置链接。如果设置了用户名和密码,它们同样以明文传输,cp-api 会在启动时记录一条警告。仅在中继位于可信内部网络时使用 none。
邀请邮件数量限制
邮件功能开启时,每个发出邀请的账号在每个滚动小时内最多可以发送 api.smtp.invitationLimitPerHour 封邀请邮件,默认为 50。该计数覆盖账号所属的所有组织,创建邀请和重新发送邀请都会计数。超出限制的请求会被拒绝,返回 429 和 Retry-After 响应头,不会创建或重新签发任何邀请。计数保存在数据库中,因此在多个 cp-api 副本之间同样生效。该限制无法关闭,最小值为 1。
请保留这项限制。每个可以发出邀请的成员都能通过你的中继向任意地址发送邮件,这项限制决定了发送量的上限。
邮件功能关闭时,不会发送任何邮件,也不会计数。
邮件语言
管理员发给他人的邮件,例如成员邀请或设置、重置密码链接,使用组织的语言编写;组织未设置语言时使用部署默认语言。你在自己浏览器中请求的邮件,例如邮箱验证或忘记密码,会优先使用该浏览器的语言选择器和浏览器语言。完整顺序参见控制台语言。
部署默认语言是 Helm 中的 ui.defaultLocale,或 Docker Compose 中的 AISIX_DASHBOARD_LOCALE。支持值为 en 和 zh。在 cp-api 配置文件中,该设置为 i18n.default_locale,AISIX_CLOUD_DEFAULT_LOCALE 变量会覆盖它。参见控制台语言。
检查中继
中继只是部署配置。控制台没有邮件设置卡片,也没有测试邮件,因此请在以下两处检查中继。
首先查看 cp-api 的启动日志。设置了中继主机时,cp-api 会在启动时记录 SMTP enabled,并附带中继的 host、port、tls 模式,以及是否进行身份认证(authenticated)。这条日志说明 cp-api 已读取并接受了这些设置,但不能说明中继可达,因为 cp-api 只在发送邮件时才连接中 继。如果没有这条日志,说明未设置主机,邮件功能处于关闭状态。
然后发送一封真实的邮件。邀请成员,例如邀请你自己的一个测试地址。邀请卡片会显示投递结果:邮件已发送到该地址,或者未发送的原因。这个结果是中继对 cp-api 的应答,并不表示邮件已到达收件箱。邮件未发送时,卡片会显示失败发生在哪一步:
| 失败类型 | 含义 |
|---|---|
| 连接 | cp-api 无法连接到中继:DNS 解析失败、连接被拒绝或中断,或超时。 |
| TLS | TLS 握手或证书校验失败,或者在 starttls 模式下中继不提供 STARTTLS。 |
| 身份认证 | 中继拒绝了配置的凭据,或没有提供 cp-api 可用的认证机制。 |
| 被拒绝 | 中继拒绝了该邮件。卡片会显示 SMTP 响应码和响应信息。 |
无论结果如何,邀请都仍然有效。检查完成后请撤销这条测试邀请。设置密码链接的卡片也会以同样方式报告其邮件的投递结果。cp-api 还会把每次投递失败记录为一条警告日志,即 invitation email not delivered 或 set-password email not delivered,并附带失败原因 reason 和 smtp_code。日志中不包含中继的响应文本,因为它经常引用收件人地址。
反向代理后的限流
登录、注册和密码重置都按客户端地址限流。默认情况下,cp-api 把连接到它的地址视为客户端。位于 Ingress 控制器或负载均衡器之后时,这个地址是代理的地址,因此所有用户共用一个限流额度,某个用户的突发请求可能导致其他用户的请求被拒绝。
如需使用真实的客户端地址,请以 CIDR 形式在 api.trustedProxies 中列出 cp-api 前方的代理;Docker Compose 中使用逗号分隔的 AISIX_TRUSTED_PROXIES。cp-api 会从右向左遍历 X-Forwarded-For 请求头,跳过位于所列范围内的每个地址,并把第一个不在范围内的地址作为客户端。只列出你自己运维的代理:列入的地址范围可以声称任意客户端地址。
api:
trustedProxies:
- 10.0.0.0/8