教程 / 后端集成 / 使用 AWS SES 发送事务邮件
📝 文字 ● 中级 更新于 2026-05-13

使用 AWS SES 发送事务邮件

每千封邮件仅需 $0.10 — 迄今最具性价比的正规邮件 API。代价是更多 AWS 风格的配置(IAM、沙盒模式退出申请、按区域 DNS 验证),以及相比开发者优先服务略显粗糙的体验。适合在 AWS 生态内、对规模化单封邮件成本极度敏感的场景。

何时选择 SES

0
  • 选择 SES 的时机 — 发送量大(每月 10 万封以上)、已在 AWS 生态内,或成本是首要因素。
  • 选择 Resend — 中小规模下配置最快、开发体验最好。
  • 选择 Postmark — 最看重收件箱到达率时。
  • 选择 SendGrid — 需要大型企业功能集时。

成本对比:SES 发送 1,000 封邮件收费 $0.10;Resend 收费 $1.00(贵 10 倍);Postmark 收费 $10(贵 100 倍)。每月发送 10 万封时,差距是 $10 对 $100 对 $1,000。SES 在成本上完胜,其他服务的优势在于节省开发时间。

在 AWS 账户中启用 SES

1

登录 AWS 控制台,搜索 SES,选择离用户最近的区域(如 us-east-1)。SES 控制台 ↗

SES 是按区域隔离的 — 验证信息和发送统计不跨区域共享。选定一个区域后请保持一致。

验证发送域名

2

SES → 已验证身份 → 创建身份 → 域。输入你的域名,选择 Easy DKIM(RSA-2048)。

SES 会生成 3 条 CNAME 记录,将它们添加到你的 DNS 服务商处。SES 每 24 小时自动检测一次,通常在一小时内完成验证。

你也可以验证单个邮件地址(用于测试):创建身份 → 电子邮件地址 → AWS 发送确认链接。操作简便但有限制;生产环境应使用域名验证。

退出沙盒模式

3

新 SES 账户默认处于沙盒模式

  • 只能向已验证的邮件地址发送邮件。
  • 每天上限 200 封。
  • 发送速率上限 1 封/秒。

这是 AWS 在你向陌生人发送邮件之前对你进行审核的机制。要退出沙盒,点击 账户面板 → 申请生产访问权限,填写表单:

  • 邮件类型 — 选择"事务性"。
  • 网站 URL — 填写你的产品网址。
  • 使用场景描述 — 务必具体。例如:"向 yourapp.com 用户发送密码重置邮件和收据。"描述模糊会被拒绝。
  • 退信/投诉处理方案 — 描述你的处理计划(见第 7 步)。

AWS 通常在 24 小时内响应,有时仅需几分钟。审批通过后初始上限为每天 5 万封,随声誉积累自动提升。

为 SES 创建 IAM 凭证

4

不要使用 AWS 根凭证。创建一个拥有最小权限策略的 IAM 用户:

  1. IAM 控制台 ↗用户 → 创建用户
  2. 用户名:ses-sender-prod(或类似名称)。
  3. 直接附加策略 → 选择 AmazonSESFullAccess(或用仅含 ses:SendEmail + ses:SendRawEmail 的内联策略进一步收紧权限)。
  4. 创建用户 → 安全凭证标签页 → 创建访问密钥 → 选择"在 AWS 外部运行的应用程序"。

将访问密钥和私密密钥保存到环境变量:

AWS_ACCESS_KEY_ID=AKIAxxxxxxxxxxxxxxxx
AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
AWS_REGION=us-east-1

如果你的应用已在 AWS 上运行(EC2、Lambda 等),请使用 IAM 角色替代长期凭证,这是 AWS 标准实践。

安装 SDK

5
npm install @aws-sdk/client-sesv2

SES 有 v1 和 v2 两套 API,请使用 v2 — 更新、默认值更合理、支持所有当前功能。其他语言:boto3、AWS SDK for Java、Go、.NET ↗

发送第一封邮件

6
import {
  SESv2Client,
  SendEmailCommand,
} from "@aws-sdk/client-sesv2";

const ses = new SESv2Client({ region: process.env.AWS_REGION });

await ses.send(new SendEmailCommand({
  FromEmailAddress: "[email protected]",
  Destination: { ToAddresses: ["[email protected]"] },
  Content: {
    Simple: {
      Subject: { Data: "Hello from AWS SES" },
      Body: {
        Text: { Data: "Plain text version" },
        Html: { Data: "<p>HTML body</p>" },
      },
    },
  },
}));

AWS SDK 会自动从环境变量或 IAM 角色读取凭证。可在 SES 控制台 → 声誉指标中查看发送统计。

处理退信与投诉(必须)

7

AWS 会暂停你的 SES 账户,若退信率超过 5% 或投诉率超过 0.1%。你必须处理这些信号。

标准配置:

  1. SES → 配置集 → 创建一个配置集,例如命名为 default-prod
  2. 配置事件目标 → 为退信和投诉事件创建 SNS 主题。
  3. 在你的应用中,为 SNS 主题订阅一个 HTTP 端点。SNS HTTP 订阅者文档 ↗
  4. 收到退信/投诉事件后,在数据库中将该收件人标记为不可发送,停止向其发送邮件。

每次发送时传入配置集名称:

await ses.send(new SendEmailCommand({
  FromEmailAddress: "[email protected]",
  Destination: { ToAddresses: ["..."] },
  Content: { /* ... */ },
  ConfigurationSetName: "default-prod",
}));

不配置此项,账户迟早会被暂停。这一步不可省略。

模板(按需使用)

8

SES 支持类 Mustache 语法的服务端模板。创建模板:

import { CreateEmailTemplateCommand } from "@aws-sdk/client-sesv2";

await ses.send(new CreateEmailTemplateCommand({
  TemplateName: "welcome",
  TemplateContent: {
    Subject: "Welcome to {{appName}}",
    Html: "<p>Hi {{name}}, welcome!</p>",
    Text: "Hi {{name}}, welcome!",
  },
}));

使用模板发送:

import { SendEmailCommand } from "@aws-sdk/client-sesv2";

await ses.send(new SendEmailCommand({
  FromEmailAddress: "[email protected]",
  Destination: { ToAddresses: [user.email] },
  Content: {
    Template: {
      TemplateName: "welcome",
      TemplateData: JSON.stringify({ name: user.name, appName: "MyApp" }),
    },
  },
}));

SES 模板功能可用,但编辑体验较为简陋。许多团队选择在应用内渲染 HTML(用 React Email、MJML 或类似工具),再将渲染结果作为字符串传给 Simple.Body.Html

SMTP 接口(SDK 不可用时)

9

SES 也提供 SMTP 凭证,适用于只支持 SMTP 协议的软件(如 WordPress、Postfix 中继、老旧系统)。

SES 控制台 → SMTP 设置 → 创建 SMTP 凭证。系统会生成专用于 SMTP 的用户名和密码。连接信息:

Host: email-smtp.us-east-1.amazonaws.com
Port: 587 (STARTTLS) or 465 (SSL)
Auth: the username/password just generated

SMTP 文档 ↗

监控声誉

10

SES 控制台 → 声誉指标

  • 退信率 — 保持在 5% 以下,超过 10% 会被暂停。
  • 投诉率 — 保持在 0.1% 以下,超过 0.5% 会被暂停。
  • 垃圾邮件投诉 — 用户在邮件客户端将你的邮件标记为垃圾邮件的次数。

为这些指标设置 CloudWatch 告警。配置得当后,AWS 会在暂停前提前通知你。若不设告警,你只会在发送中断时才发现问题。

常见故障

11
  • "Email address not verified" — 仍处于沙盒模式,或从未验证的地址发送。验证域名(第 2 步)或退出沙盒(第 3 步)。
  • "AccessDenied" — IAM 用户缺少 ses:SendEmail 权限,更新策略即可。
  • "MessageRejected" — 邮件体过大(上限 10 MB)、不支持的字符编码,或配置集不存在。
  • "Throttling" — 超过账户发送速率上限。在账户面板查看当前限制,声誉积累后会自动提升。
  • 沙盒模式邮件正常但生产模式邮件丢失 — 区域不匹配。SES 按区域隔离,客户端必须与验证时使用的区域一致。
SES 是所有邮件 API 中最"AWS 味"的一个。学习过程中你需要了解一些 IAM、CloudWatch 和 SNS 的知识。如果你还不熟悉 AWS,Resend 或 Postmark 可以让你在 5 分钟内开始发送;SES 可能需要 2 小时。但换来的回报是规模化场景下 10 至 100 倍的成本优势。

定价实况

12

每 1,000 封外发邮件收费 $0.10;每 1,000 封接收邮件收费 $0.10(如启用接收);附件每 GB 收费 $0.12。

免费额度:从 EC2 实例发送时,每月可免费发送 62,000 封邮件。其他情况从第 1 封起计费(但 $0.10/千封已经足够便宜,差异几乎可以忽略)。

SES 定价 ↗

官方参考资料

下一步