Skip to main content
让 Sentra 为您编写集成代码。
在 VS Code、Cursor 或 Windsurf 中使用我们的 AI 助手,只需描述您的需求即可生成 SDK/API 代码、webhook 处理程序等。
尝试 Sentra:AI 驱动的集成 →
在本教程中,您将构建 MailKit,这是一个交易邮件平台,客户可以预先购买一组电子邮件信用。该计划提供每月的电子邮件额度;当客户余额不足时,他们可以购买充值包,而不是等待下一个周期。每次发送会自动扣除一个信用。
本教程使用 Resend 作为电子邮件提供商。其免费套餐(每月 3,000 封邮件)足以在没有付费账户的情况下构建和测试整个流程。该模式适用于任何提供商;可以用 SendGrid、Postmark、SES 或您自己的 SMTP 中继替换 resend.emails.send
在本教程结束时,您将了解如何:
  • 在您的仪表板中创建自定义信用权利(电子邮件)
  • 将信用附加到订阅计划和一次性充值产品上
  • 通过 Resend 发送真实电子邮件,并通过账本条目每发送一次扣减一个信用
  • 从您的前端查询实时信用余额
  • 正确验证 Dodo webhooks,并在客户接近零之前处理 credit.balance_low 发出信号

我们正在构建的内容

以下是 MailKit 的定价模型: 单位为 一封电子邮件 = 一信用。客户无需考虑令牌、批量或加权单位。他们只需看到“您本月还剩 4,231 封邮件”。
在开始之前,请确保您有:
  • 一个 Dodo Payments 账户(测试模式即可)
  • 一个免费的 Resend 账户和 API 密钥
  • Node.js 18+ 和基本的 TypeScript 知识

第 1 步:创建您的电子邮件信用权利

信用权利定义了您的平台出售的单位:在这种情况下为一次电子邮件发送。
信用列表页面

The Credits tab under Products lists all your credit entitlements.

1

Open the Credits section

  1. 登录您的 Dodo Payments 仪表板
  2. 点击左侧边栏中的 产品
  3. 选择 信用 标签
  4. 点击 创建信用
2

Configure the credit unit

填写信用详情:信用名称: Email Credits信用类型: 选择 Custom Unit单位名称: email精度: 0(电子邮件始终为整单位;您无法发送半封邮件)信用过期: 30 days(每个周期的额度重置)
精度在创建后不能更改。对于离散单位如电子邮件、消息或会话,0 是正确的。
3

Leave the other defaults as-is

在本食谱中我们不会启用滚动或超量;目标是实现最简单的 CBB 流程。您可以稍后在信用附件上重新访问这些选项。
4

Save and copy the credit ID

点击 创建信用。打开信用并复制其 ID。您需要它用于后端余额查询。看起来像 cent_xxxxxxxxxxxx
您的 Email Credits 权利已准备好。接下来:授予客户信用的产品。

第 2 步:创建计划和充值包

您将创建两个产品:一个定期的 订阅 计划和一个 一次性付款 充值。该计划授予每个周期 5,000 封电子邮件;充值可按需增加 5,000 封。两者都附加相同的 Email Credits 权利。
此食谱通过直接账本条目而非基于使用的计量器来扣除信用。账本条目是即时的(余额在毫秒内更新),无需额外设置,当一个用户动作等于准确一个信用时这是合适的选择。如果您更喜欢从摄取的使用事件中自动扣除(适用于加权单位如“令牌”或“已处理 MB”),请参阅 Credit-Based Billing → Usage Billing with Credits 获取基于计量器的模式。

MailKit 计划 ($19/月,5,000 封邮件)

1

Create the subscription

  1. 进入 产品 → 创建产品
  2. 填写产品详情:
产品名称: MailKit Plan描述: 5,000 transactional emails per month.
  1. 选择 订阅 作为产品类型
  2. 设置经常性价格:
经常性价格: 19.00计费周期: Monthly货币: USD
2

Attach the email credit entitlement

滚动到 权利 → 信用 → 附加 并配置:信用权利: Email Credits每个计费周期发行的信用: 5000低余额阈值: 20(百分比;当余额低于周期额度的 20% 时触发 credit.balance_low,即 1,000 封邮件)导入默认信用设置: 启用(使用第 1 步的 30 天到期)点击 添加到产品,然后 保存 产品。复制产品 ID (pdt_xxxxxxxxxxxx)。
计划:$19/月 → 每个周期刷新 5,000 封邮件。

充值包 ($9 一次性,5,000 封邮件)

1

Create a one-time product

  1. 进入 产品 → 创建产品
  2. 填写产品详情:
产品名称: Email Top-Up Pack描述: Add 5,000 emails to your MailKit balance instantly.
  1. 选择 一次性付款 作为产品类型
  2. 设置价格:
价格: 9.00货币: USD
2

Attach the credit grant

权利 → 信用 → 附加
  • 信用权利: Email Credits
  • 发放的信用: 5000
一次性产品根据其自身的到期(购买后 30 天,从第 1 步开始)授予信用。充值在订阅信用之上叠加;它们不会替代它们。
保存并复制产品 ID。
充值包:$9 → +5,000 封邮件,立即可用。

第 3 步:设置后端

现在构建处理结账、发送、余额查询和 webhooks 的 Express 服务器。
1

Initialize the project

将一个开发脚本添加到 package.json
tsx 直接运行 TypeScript,无需构建步骤或 tsconfig.json,这对于教程是完美的。对于生产环境,添加一个 tsconfig.json 和一个 build 脚本。
2

Configure environment variables

创建 .env
.env
您将在第 4 步创建端点后填充 DODO_WEBHOOK_KEY。Resend API 密钥来自 resend.com/api-keys
立即在 .gitignore 中添加 .env。切勿提交 API 密钥。
3

Build the server

在项目根目录中创建 server.ts
Webhook 消息体必须是原始的。 express.json() 解析并重新序列化消息体,这会导致签名验证失败。定义 /webhooks/dodoexpress.raw() app.use(express.json()) 之前。
后端准备就绪:订阅、充值、余额、发送以及 webhook 处理程序已全部连接。
4

Add a demo UI

创建 public/index.html

第 4 步:连接 Webhook 端点

credit.balance_low 事件是让您在客户用完之前提示他们的重要事件。没有它,他们第一次注意到问题是在发送邮件失败时。
1

Expose your local server

Webhooks 需要一个公共 URL。使用 ngrok(或任何隧道)在开发时运行:
复制 HTTPS 转发 URL(例如 https://1234abcd.ngrok-free.app)。
2

Register the endpoint in Dodo

  1. 进入 开发者 → Webhooks → 添加端点
  2. URL: https://1234abcd.ngrok-free.app/webhooks/dodo
  3. 事件: 订阅 credit.added, credit.balance_lowcredit.rolled_over
  4. 保存,然后将 签名密钥 复制到您的 .env 作为 DODO_WEBHOOK_KEY
  5. 重启服务器

第 5 步:测试完整流程

1

Start the server

您应该会看到 MailKit running on http://localhost:3000。在浏览器中打开它。
2

Subscribe a test customer

  1. 在第 1 节中输入测试电子邮件和名称,点击 获取结账链接
  2. 打开链接,用测试卡完成结账
  3. 付款后,在仪表板下的 客户 中找到 customer_id
客户现在应该在其余额中有 5,000 封电子邮件。检查 客户 → [客户] → 信用
3

Send a real email

  1. customer_id 粘贴到第 3 节
  2. 保持 to 设置为 delivered@resend.dev(Resend 的沙盒邮箱,接受所有内容)
  3. 点击 发送
您将获得返回的 Resend 消息 ID。在第 2 节中刷新余额,数量会立即下降到 4,999。每次账本扣款都会立即反映在实时余额中。
4

Trigger the low-balance webhook

阈值为 20%(5,000 封邮件额度的 1,000 封)。要触发它而无需发送 4,000 封真实邮件,手动从仪表板扣减余额
  1. 进入 客户 → [客户] → 信用 → 邮件信用
  2. 点击 调整余额 并扣减 4000
  3. 再通过演示发送一封邮件
您的服务器应在几秒钟内记录:
您的服务器已接收到并验证了 webhook。在生产中,这就是您向客户发送电子邮件或显示应用内横幅的地方。
5

Buy a top-up pack

  1. customer_id 粘贴到第 4 节
  2. 点击 购买 5,000 封邮件,完成测试结账
  3. 刷新余额,它会跳增 5,000
grant_source: one_time 触发 credit.added 事件。充值叠加在订阅信用之上;两个池按 FIFO 消耗(最早的未过期供给首先使用)。
6

Test the hard stop

手动扣减余额到零,然后尝试再发送一封电子邮件。您将收到:
那个 402 是您的应用程序级别的强制。Dodo 余额 API 是事实来源;切勿在客户端缓存它。

故障排除

签名是通过原始 HTTP 消息体计算的。express.json() 解析并重新序列化有效负载,这会打破 HMAC。确保 /webhooks/dodo 使用 express.raw({ type: 'application/json' }) app.use(express.json()) 行上注册,并且 DODO_WEBHOOK_KEY 匹配端点详情页面上显示的签名密钥。
需要验证的三件事,按以下顺序:
  1. 客户 完成结账(信用在成功付款时发放,而不是在会话创建时)
  2. CREDIT_ENTITLEMENT_ID 在您的 .env 中与产品附加的信用匹配(不匹配的 ID 会静默写入错误的信用)
  3. 您传递的 customer_id 来自 Dodo(仪表板中的 customers 表),而不是您自己的数据库
沙盒发件人 onboarding@resend.dev 仅传递到您 Resend 账户上的电子邮件或 delivered@resend.dev。要发送给其他人,验证一个域名 并使用其上的 from 地址。

您构建了什么

One reusable credit unit

Email Credits,一次定义并附加到订阅计划和充值包上。

Subscription with prepaid allowance

$19/月授予每个周期 5,000 封邮件。客户知道他们的支出,您知道您的最坏成本。

Top-up pack

一个一次性产品,授予 5,000 封邮件。无需更改计划即可叠加订阅信用。

Instant ledger debits

每次发送后的一个简单 createLedgerEntry 调用。没有计量器,没有聚合滞后,通过 Resend 的消息 ID 在重试时具备幂等性。

Credit-Based Billing Reference

阅读完整的 CBB 文档,了解滚动、超量模式、账本管理和完整的 API 资源。
需要帮助?
最后修改于 2026年5月13日