跳到主要内容
版本:1.6.0

配置邮件(SMTP)

On-Premises 控制面可以通过你自行运维或订阅的 SMTP 中继发送邮件。只有 cp-api 会发送邮件,它使用中继发送三类邮件:

  • 邀请邮件。 管理员邀请成员时,邀请链接会通过邮件发给受邀人。参见邀请成员。
  • 密码重置邮件。 忘记密码的用户可以在登录页申请重置链接。参见重置忘记的密码。
  • 设置密码邮件。 管理员为成员启用登录或重置成员密码时,一次性链接会通过邮件发给该成员。参见启用登录或重置密码。

在设置中继主机之前,邮件功能处于关闭状态。此时,控制台会显示每条邀请链接和设置密码链接,由管理员手动转交;忘记密码页面会提示用户联系管理员。

设置​

使用 Helm 配置值配置中继;Docker Compose 安装则在 ./aisix-self-hosted/.env 中配置:

Helm 配置项Docker Compose 变量作用
api.smtp.hostAISIX_CLOUD_SMTP_HOST中继主机名。默认留空,表示关闭邮件功能。
api.smtp.tlsAISIX_CLOUD_SMTP_TLS连接的保护方式:starttls(默认)、smtps 或 none。参见连接安全。
api.smtp.portAISIX_CLOUD_SMTP_PORT中继端口。未设置时按 TLS 模式取值:starttls 为 587,smtps 为 465,none 为 25。
api.smtp.fromAISIX_CLOUD_SMTP_FROM所有邮件的发件人地址,例如 AISIX <noreply@example.com>。设置了主机时必填。
api.smtp.usernameAISIX_CLOUD_SMTP_USERNAMESMTP 身份认证的用户名。可选,参见身份认证。
api.smtp.password,或 api.smtp.existingSecret 与 api.smtp.existingSecretKeyAISIX_CLOUD_SMTP_PASSWORDSMTP 身份认证的密码。Chart 会把 api.smtp.password 存放在自己的 Secret 中,或者从已有 Secret 中读取 api.smtp.existingSecretKey 指定的键(默认为 smtp-password)。
api.smtp.invitationLimitPerHourAISIX_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'
values.yaml
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 也不会进行认证:

values.yaml
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 解析失败、连接被拒绝或中断,或超时。
TLSTLS 握手或证书校验失败,或者在 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 请求头,跳过位于所列范围内的每个地址,并把第一个不在范围内的地址作为客户端。只列出你自己运维的代理:列入的地址范围可以声称任意客户端地址。

values.yaml
api:
trustedProxies:
- 10.0.0.0/8

后续步骤​

邀请和密码重置对用户的具体表现参见成员,其他控制面设置参见私有化部署配置。