随记

给个人项目接入邮箱验证码:一次腾讯云 SES 配置记录

最近给个人项目补账号系统时,需要实现邮箱注册和验证码验证。项目服务器在腾讯云,域名 XXXX.com 托管在阿里云,因此邮件服务直接选择了腾讯云 SES。

整个过程并不复杂,但涉及域名验证、DNS、邮件模板、API 权限和后端调用,第一次配置时还是有几个容易踩坑的地方。

1. 先配置发信域名

在腾讯云 SES 中新建发信域名:

1
mail.xxxx.com

这里的 mail.xxxx.com 不需要单独购买,它只是 xxxx.com 的一个子域名。

腾讯云会要求验证这个域名,并给出一组 DNS 记录,主要包括:

1
2
3
4
MX
SPF
DKIM
DMARC

腾讯云 SES 要求这些记录保持正确配置,否则可能影响后续发信。(腾讯云)

由于域名的 DNS 在阿里云管理,所以接下来进入阿里云云解析 DNS,把腾讯云提供的记录逐条添加进去。

例如腾讯云要求添加:

1
2
3
类型:TXT
主机记录:mail
记录值:v=spf1 ...

在阿里云中就直接选择 TXT,主机记录填写 mail,不需要再写完整的:

1
mail.xxxx.com

阿里云会自动拼接主域名。(阿里云帮助中心)

DKIM 也是 TXT 记录,不过主机记录通常类似:

1
xxxx._domainkey.mail

记录值则是一段比较长的公钥:

1
v=DKIM1; k=rsa; p=......

这里最好完全复制腾讯云提供的内容,不要自己修改,也不要手动换行。

image-20260908145109247

配置完成后等待 DNS 生效,再回腾讯云重新验证。腾讯云文档说明 DNS 配置同步可能需要几分钟到数小时。(腾讯云)

最终看到:

image-20260908145242070

1
2
mail.xxxx.com
已验证

发信域名这一部分就完成了。

2. 创建发信地址和验证码模板

域名验证完成后,可以创建真正的发件地址,例如:

1
no-reply@mail.xxxx.com

邮件显示名称设置为:

1
也祝日志

之后创建一个验证码邮件模板,正文保持简单即可:

1
2
3
4
5
6
7
8
9
<h2>也祝日志</h2>

<p>本次邮箱验证码为:</p>

<h1>{{code}}</h1>

<p>验证码 10 分钟内有效,请勿泄露给他人。</p>

<p>如果并非本人操作,请忽略此邮件。</p>

这里 {{code}} 是动态变量。后端真正发邮件时,只需要传入:

1
2
3
{
"code": "583921"
}

模板审核通过以后,就可以正式通过 API 发送验证码。

3. API 密钥不要直接使用主账号

后端调用腾讯云 SES 需要:

1
2
SecretId
SecretKey

一开始比较容易想到直接创建腾讯云主账号 API 密钥,但这样权限过大。更合适的方式是在腾讯云 CAM 中创建一个专用子用户:

1
yizhu-ses

只开启:

1
编程访问

并创建一个最小权限策略:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"version": "2.0",
"statement": [
{
"effect": "allow",
"action": [
"ses:SendEmail"
],
"resource": [
"*"
]
}
]
}

这样这个密钥只能调用 SES 发邮件,即使意外泄露,也不会直接获得云服务器、数据库等其他资源的管理权限。

4. 把配置放进服务器 .env

项目使用 FastAPI,所有敏感配置都放在服务器环境变量中:

1
2
3
4
5
6
TENCENT_SECRET_ID=xxxx
TENCENT_SECRET_KEY=xxxx

TENCENT_SES_REGION=ap-hongkong
TENCENT_SES_FROM=no-reply@mail.XXXX.com
TENCENT_SES_TEMPLATE_ID=xxxx

前端无论是 Web、PWA 还是微信小程序,都不应该直接拿到腾讯云密钥。正确链路应该是:

1
2
3
4
5
6
7
前端
↓
FastAPI
↓
腾讯云 SES
↓
用户邮箱

而不是:

1
2
3
前端
↓
腾讯云 SES

5. FastAPI 调用 SES

腾讯云 SES 提供 SendEmail 接口,适用于验证码这类触发邮件,请求域名为:

1
ses.tencentcloudapi.com

目前该接口支持 ap-guangzhou 和 ap-hongkong 两个 Region。(腾讯云)

第一次接入时没有直接开始做完整注册系统,而是先写一个最小测试:

1
2
3
4
5
6
7
FastAPI
↓
固定验证码 123456
↓
腾讯云 SES
↓
自己的邮箱

模板参数:

1
2
3
{
"code": "123456"
}

发送成功后,SES 返回 MessageId,邮箱也实际收到验证码:

1
2
3
【也祝日志】邮箱验证码

123456

到这里才确认整条邮件链路真正跑通。

几个比较值得记录的点

域名、服务器和邮件服务并不要求必须在同一家云厂商。域名在阿里云、服务器和 SES 在腾讯云完全可以正常使用,本质上只需要在实际 DNS 服务商配置腾讯云要求的记录即可。腾讯云官方也明确支持域名托管在其他服务商的情况。(腾讯云)

另外,邮件验证中最容易出问题的是 DKIM。SPF、DMARC 验证比较直观,而 DKIM 的主机记录和公钥比较长,复制时少一个字符都可能验证失败。

最后是安全问题。验证码系统真正上线后还不能只做到“随机生成六位数字”,还需要增加:

1
2
3
4
5
6
7
验证码 10 分钟失效
60 秒内禁止重复发送
验证码只允许使用一次
限制错误尝试次数
限制同邮箱/IP发送频率
数据库只保存验证码 Hash
密码使用 Argon2id 等安全哈希

邮件发送只是账号系统中的一小段,但把这一段独立测试通之后,后面的注册、登录和找回密码都会简单很多。

腾讯云相关文档可以参考:腾讯云 SES 邮件配置、SendEmail API;DNS 配置可以参考 阿里云公网 DNS 解析记录说明。