name: tencent-ses-service version: 1.1.0 description: | 腾讯云官方的邮件推送 SES 服务使用 skill。 涵盖:SMTP 发送邮件所需的全部环境变量、API 接口设计规范、验证码邮件的完整发送流程(含人机验证、频率控制、Redis 存储)。 本 skill 以网络协议 / HTTP API 接口级别描述,不绑定具体编程语言。 model: deepseek-chat tags: - SES - SMTP - 腾讯云 - 邮件推送 - 验证码 - Redis rootUrl: https://raw.githubusercontent.com/LSTM-Kirigaya/jinhui-skills/main/skills/tencent-ses-service/SKILL.md allowed-tools: - Read - Write - Edit - Bash - Grep - Glob
腾讯云邮件推送 SES 服务
本 skill 描述如何通过腾讯云 SES(Simple Email Service)的 SMTP 协议 发送邮件。腾讯云 SES 提供两种接入方式:API SDK 方式(SendEmail 接口)和 SMTP 方式。本文档基于 SMTP 方式,因为它不依赖腾讯云 SDK,通用性更强。
一、前置条件
1.1 开通腾讯云 SES 服务
在腾讯云控制台开通 SES 服务,完成发件域名配置和 DKIM/SPF 验证。
- 控制台地址:
https://console.cloud.tencentcloud.com/ses - 发件域名需要已备案且通过 DNS 验证
- 配置完成后获取 SMTP 凭据(见下方环境变量)
1.2 依赖的外部服务
| 服务 | 用途 |
|---|---|
| Redis | 存储验证码(含过期时间)、滑块验证 token、频率控制标记 |
| 滑块验证服务 | 生成并校验人机验证 token(本项目使用腾讯云验证码服务) |
二、环境变量
以下环境变量为必填项,缺一不可:
| 变量名 | 示例值 | 说明 |
|---|---|---|
TENCENTCLOUD_SMTP_HOST |
smtp.qcloudmail.com |
腾讯云 SES SMTP 服务器地址 |
TENCENTCLOUD_SMTP_PORT |
465 |
SMTP 端口。465 为 SSL 直连,587 为 STARTTLS |
TENCENTCLOUD_SMTP_USER |
noreply@healthymax.cn |
SMTP 认证用户名(即发件邮箱地址) |
TENCENTCLOUD_SMTP_PASSWORD |
WDWOPKOPkop12312dko |
SMTP 认证密码(在腾讯云 SES 控制台生成,非邮箱登录密码) |
SMTP 密码获取方式
- 登录腾讯云 SES 控制台
- 进入「发件域名」→ 选择已配置的域名
- 点击「SMTP 密码」→「生成密码」
- 记录生成的密码(只显示一次)
三、API 接口设计
3.1 发送验证码邮件
端点: POST /api/ses/send-verification-code
认证要求: 无需登录态(公开接口),但需要滑块验证 token。
请求体(JSON)
字段 类型 必填 说明
────────────────────────────────────────────────
email string 是 收件人邮箱地址
captchaToken string 是 滑块验证通过后获得的 token
请求示例(仅供参考,非特定语言):
{
"email": "user@example.com",
"captchaToken": "abc123def456..."
}
响应体(JSON)
成功时 HTTP 200:
{
"success": true,
"message": "验证码发送成功",
"data": {
"requestId": "<messageId from SMTP server>"
}
}
失败时返回对应 HTTP 状态码(400/429/500):
{
"success": false,
"message": "错误描述",
"data": null
}
错误码一览
| HTTP 状态码 | message | 触发条件 |
|---|---|---|
| 400 | 邮箱地址不能为空 |
email 字段缺失或为空 |
| 400 | 邮箱格式不正确 |
email 不符合正则 ^[^\s@]+@[^\s@]+\.[^\s@]+$ |
| 400 | 请先完成滑块验证 |
captchaToken 未传 |
| 400 | 验证已过期,请重新完成滑块验证 |
captcha token 在 Redis 中不存在或已过期 |
| 429 | 发送验证码过于频繁,请稍后再试 |
同一邮箱或同一 IP 在 30 秒内重复请求 |
| 500 | 验证服务不可用 |
Redis 连接不可用 |
| 500 | 发送邮箱验证码异常: ... |
SMTP 发送失败(携带具体错误信息) |
四、发送流程(网络接口级描述)
整体时序
客户端 服务端 Redis SMTP 服务器
│ │ │ │
│ POST /api/ses/send- │ │ │
│ verification-code │ │ │
│ {email, captchaToken} │ │ │
│ ────────────────────────────▶ │ │ │
│ │ GET captcha:token:{token} │ │
│ │ ──────────────────────────────▶ │ │
│ │ ◀────────────────────────────── │ │
│ │ DEL captcha:token:{token} │ │
│ │ ──────────────────────────────▶ │ │
│ │ │ │
│ │ GET throttle:email:{email} │ │
│ │ ──────────────────────────────▶ │ │
│ │ GET throttle:email:ip:{ip} │ │
│ │ ──────────────────────────────▶ │ │
│ │ │ │
│ │ SETEX email_verification_code: │ │
│ │ {email} 900 {code} │ │
│ │ ──────────────────────────────▶ │ │
│ │ SETEX throttle:email:{email} │ │
│ │ 30 {timestamp} │ │
│ │ ──────────────────────────────▶ │ │
│ │ SETEX throttle:email:ip:{ip} │ │
│ │ 30 {timestamp} │ │
│ │ ──────────────────────────────▶ │ │
│ │ │ │
│ │ EHLO / STARTTLS / AUTH LOGIN │ │
│ │ ─────────────────────────────────────────────────▶ │
│ │ MAIL FROM / RCPT TO / DATA │ │
│ │ ─────────────────────────────────────────────────▶ │
│ │ ◀───────────────────────────────────────────────── │
│ │ │ │
│ ◀────────────────────────────│ │ │
│ {success: true, │ │ │
│ data: {requestId: "..."}} │ │ │
步骤详解
Step 1:参数校验
- 检查
email非空 - 检查
email匹配格式正则^[^\s@]+@[^\s@]+\.[^\s@]+$ - 检查
captchaToken非空 - 检查 Redis 连接可用
Step 2:滑块验证
- 从 Redis 读取 key:
captcha:token:{captchaToken} - 读取后立即删除该 key(一次性使用,防重放)
- 若 key 不存在或已过期 → 返回 400,要求用户重新完成滑块验证
Step 3:频率控制(双重节流)
检查两个 Redis key,任一存在即返回 429:
| Redis Key | TTL | 含义 |
|---|---|---|
throttle:email:{email} |
30s | 同一邮箱 30 秒内只能发送一次 |
throttle:email:ip:{clientIP} |
30s | 同一 IP 30 秒内只能发送一次 |
客户端 IP 从请求头
X-Forwarded-For的第一个值获取,无代理时回退为127.0.0.1。
Step 4:生成验证码并存入 Redis
- 生成 6 位随机数字验证码(范围 100000-999999)
- 存入 Redis:
SETEX email_verification_code:{email} 900 {code}- TTL = 900 秒(15 分钟)
- 设置节流标记:
SETEX throttle:email:{email} 30 {timestamp}SETEX throttle:email:ip:{ip} 30 {timestamp}
Step 5:通过 SMTP 发送邮件
连接到腾讯云 SMTP 服务器并发送邮件。SMTP 会话参数:
| 参数 | 值 | 说明 |
|---|---|---|
| Host | {TENCENTCLOUD_SMTP_HOST} |
腾讯云 SMTP 服务器 |
| Port | {TENCENTCLOUD_SMTP_PORT} |
465(SSL)或 587(STARTTLS) |
| Secure | true(465 端口)/ false(587 端口) |
是否使用 SSL 直连 |
| Auth User | {TENCENTCLOUD_SMTP_USER} |
SMTP 认证用户名 |
| Auth Pass | {TENCENTCLOUD_SMTP_PASSWORD} |
SMTP 认证密码 |
邮件信封(SMTP MAIL FROM / RCPT TO):
| 字段 | 值 |
|---|---|
| MAIL FROM | noreply@{发件域名} 实际地址为 {TENCENTCLOUD_SMTP_USER} |
| RCPT TO | 请求参数中的 email |
| From (header) | "noreply@{域名}" <{TENCENTCLOUD_SMTP_USER}> |
| To (header) | 请求参数中的 email |
| Subject | 邮箱验证 - 智健启能 |
Step 6:返回结果
- 成功:返回 HTTP 200,
data.requestId为 SMTP 服务器返回的messageId - 失败:返回 HTTP 500,
message包含 SMTP 错误详情
Step 7:客户端校验验证码
客户端后续可通过独立的验证接口校验验证码(读取 Redis key email_verification_code:{email} 并比对),验证通过后删除该 key。
五、邮件内容规范
HTML 邮件结构
邮件正文使用 HTML 格式,建议遵循以下规范:
结构层次:
├── 外层容器(最大宽度 600px,圆角 24px,白色背景)
│ ├── Header:Logo 图片 + 产品名称
│ ├── Divider:1px 分割线
│ ├── Body:
│ │ ├── 标题(如"安全验证")
│ │ ├── 说明文字
│ │ ├── 验证码展示区(灰底圆角卡片,等宽字体居中展示 6 位数字)
│ │ └── 过期提示
│ └── Footer:安全提示 + 版权信息
设计约束
- 移动端适配:使用
@media only screen and (max-width: 600px)覆盖容器宽度和圆角 - 字体栈:
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif - 验证码字体:等宽字体(
Monaco, Consolas, monospace),字间距0.2em - 品牌色:主色
#f6993b(橙),文字色#1E293B/#64748B,背景#F8FAFC
HTML 邮件模板示例
⚠️ 以下为 HTML 结构说明,具体内容请根据项目品牌调整。代码仅为示意,不绑定任何编程语言。
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"></head>
<body style="margin:0;padding:0;background-color:#F8FAFC;font-family:-apple-system,...">
<table width="100%"><tr><td align="center" style="padding:40px 20px;">
<table width="600" style="background:#fff;border-radius:24px;...">
<!-- Header: Logo + 产品名 -->
<tr><td>...</td></tr>
<!-- Body: 标题 + 说明 + 验证码 + 过期时间 -->
<tr><td>...</td></tr>
<!-- Footer: 安全提示 + 版权 -->
<tr><td>...</td></tr>
</table>
</td></tr></table>
</body>
</html>
模板命名与链接规范
模板命名要求
模板名称必须清晰表明邮件的具体用途,禁止使用模糊不清、无法判断用途的命名。
| 合法性 | 示例 | 说明 |
|---|---|---|
| ✅ 合法 | 注册验证码邮件 |
明确表明用途为「注册」场景的验证码邮件 |
| ✅ 合法 | 密码重置确认邮件 |
明确表明用途为「密码重置」场景 |
| ❌ 非法 | 邮件发送 |
过于笼统,无法判断具体用途 |
| ❌ 非法 | 通知邮件 |
未说明通知的具体类型和场景 |
平台审核时会检查模板名称的明确性,命名不清将直接导致审核驳回。
链接填写要求
HTML 模板中的链接必须包含完整域名,仅允许对路径或参数部分使用模板变量。禁止出现将完整 URL(含协议和域名)整体替换为变量的情况。
| 合法性 | 示例 | 说明 |
|---|---|---|
| ✅ 合法 | https://kirigaya.cn/blog/article?seq={{id}} |
域名完整,仅参数部分为变量 |
| ✅ 合法 | https://healthymax.cn/verify?token={{token}} |
域名完整,仅查询参数为变量 |
| ❌ 非法 | {{url}} |
完整 URL 被变量替代,无法审核域名归属 |
| ❌ 非法 | {{baseUrl}}/path |
协议和域名部分被变量替代 |
此要求用于方便平台审核链接指向的域名归属及内容合规性。请在提交审核前完成自检。
六、Redis Key 设计汇总
| Key Pattern | 类型 | TTL | 用途 |
|---|---|---|---|
captcha:token:{token} |
任意 | 由滑块服务设定 | 人机验证 token(验证后删除) |
throttle:email:{email} |
String (timestamp) | 30s | 邮箱维度的发送频率控制 |
throttle:email:ip:{ip} |
String (timestamp) | 30s | IP 维度的发送频率控制 |
email_verification_code:{email} |
String (6位数字) | 900s (15min) | 邮箱验证码存储 |
七、前端调用约定
触发验证码发送的前置条件
客户端在调用 POST /api/ses/send-verification-code 前,必须:
- 用户已完成滑块验证 → 获得
captchaToken - 用户输入的邮箱格式已通过前端初步校验
调用模式
前端组件 sesService API Route
│ │ │
│ sendVerificationCode() │ │
│ ─────────────────────────▶ │ │
│ │ POST /api/ses/ │
│ │ send-verification-code │
│ │ ───────────────────────────▶ │
│ │ ◀─────────────────────────── │
│ ◀───────────────────────── │ │
示例代码(仅为说明调用模式,不涉及具体语言):
service.sendVerificationCode({ email: "user@example.com", captchaToken: "xxx" })
消费者场景
验证码邮件在以下场景被触发:
| 场景 | 说明 |
|---|---|
| 用户注册 | 输入邮箱后发送验证码 |
| 邮箱登录 | 选择邮箱验证码登录模式 |
| 修改密码 | 向已绑定的邮箱发送验证码 |
| 绑定/更换邮箱 | 向新邮箱发送验证码以确认所有权 |
八、常见问题
Q: 为什么选择 SMTP 方式而非 API SDK?
SMTP 方式不依赖 tencentcloud-sdk-nodejs,使用标准的 SMTP 协议(RFC 5321),可以对接任何支持 SMTP 的邮件库。腾讯云 SES API SDK(SendEmail 接口)需要 SecretId/SecretKey 签名认证,而 SMTP 方式只需用户名密码,部署更简单。
Q: 端口 465 vs 587 如何选择?
- 465(SSL):SMTP over SSL,连接即加密,推荐使用
- 587(STARTTLS):先明文连接再升级 TLS,部分云环境防火墙兼容性更好
本 skill 使用 465 端口 + secure: true。
Q: SMTP 密码和腾讯云 API SecretKey 是同一个吗?
不是。 SMTP 密码是在 SES 控制台单独生成的,仅用于 SMTP 认证。API SecretKey 用于调用腾讯云其他 API(如 SMS 短信服务),两者独立。
Q: 如何扩展为发送其他类型的邮件?
在现有 SMTP 连接基础上,只需构造不同的 Subject 和 html 内容即可发送任意事务邮件。注意:
- 发件地址必须使用已配置的发件域名
- 腾讯云 SES 对发送频率和内容有审核要求
- 建议为不同类型的邮件也加入 Redis 节流控制
九、安全检查清单
- SMTP 凭据(
TENCENTCLOUD_SMTP_PASSWORD)仅存储在服务端环境变量,不暴露给前端 - 发送验证码前必须校验滑块验证 token
- 验证码存储使用 Redis TTL 自动过期
- 双重频率控制(邮箱 + IP),防止短信轰炸
- 滑块验证 token 一次性使用(读后即删),防重放攻击
- 接口路径加入公开白名单(如反向代理配置)以允许未登录用户访问
- 邮件内容中的链接使用 HTTPS
- 邮件模板名称清晰明确,能够直接判断邮件用途(如「注册验证码邮件」合法,「邮件发送」非法)
- 邮件模板中的链接包含完整域名,未将协议+域名部分整体替换为变量(如
{{url}}非法,https://example.com/path?id={{id}}合法)