resend.emails.sendをSendGrid、Postmark、SES、または独自のSMTPリレーに置き換えてください。- ダッシュボードでカスタムクレジットエンタイトルメント(メール)を作成する
- クレジットをサブスクリプションプランとワンタイムトップアッププロダクトに関連付ける
- Resend経由で実際のメールを送信し、ledgerエントリによって送信ごとに1クレジットを差し引く
- フロントエンドから最新のクレジット残高を取得する
- Dodo webhookを正しく検証し、
credit.balance_lowを処理して残高がゼロになる前に顧客へ通知する
構築するもの
MailKitの料金モデルは次のとおりです。- Dodo Paymentsアカウント(test modeで問題ありません)
- 無料のResendアカウントとAPI key
- Node.js 18以降とTypeScriptの基本的な知識
Step 1:メールクレジットエンタイトルメントを作成する
クレジットエンタイトルメントは、プラットフォームが販売する単位を定義します。ここでは、メール1通の送信です。
The Credits tab under Products lists all your credit entitlements.
Open the Credits section
- Dodo Paymentsダッシュボードにログインします
- 左側のサイドバーでProductsをクリックします
- Creditsタブを選択します
- Create Creditをクリックします
Configure the credit unit
Email CreditsCredit Type: Custom Unitを選択しますUnit Name: emailPrecision: 0(メールは常に整数単位であり、半分のメールを送信することはできません)Credit Expiry: 30 days(各サイクルで利用枠がリセットされます)Leave the other defaults as-is
Save and copy the credit ID
cent_xxxxxxxxxxxxのようになります。Email Creditsエンタイトルメントの準備ができました。次は、顧客にクレジットを付与するプロダクトを作成します。Step 2:プランとトップアップパックを作成する
2つのプロダクトを作成します。定期的なSubscriptionプランと、ワンタイムのSingle Paymentトップアップです。プランでは各サイクルに5,000通を付与し、トップアップでは必要に応じてさらに5,000通を追加します。どちらも同じEmail Creditsエンタイトルメントを関連付けます。
MailKit Plan(月額$19、5,000通)
Create the subscription
- Products → Create Productに移動します
- プロダクトの詳細を入力します。
MailKit PlanDescription: 5,000 transactional emails per month.- プロダクトタイプとしてSubscriptionを選択します
- 定期料金を設定します。
19.00Billing Cycle: MonthlyCurrency: USDAttach the email credit entitlement
Email CreditsCredits issued per billing cycle: 5000Low Balance Threshold: 20(パーセント。残高がサイクルの利用枠の20%、つまり1,000通を下回ったときにcredit.balance_lowを発生させます)Import Default Credit Settings: 有効(Step 1の30日間のexpiryを使用)Add to Productをクリックし、プロダクトをSaveします。プロダクトID(pdt_xxxxxxxxxxxx)をコピーします。Top-Up Pack(ワンタイム$9、5,000通)
Create a one-time product
- Products → Create Productに移動します
- プロダクトの詳細を入力します。
Email Top-Up PackDescription: Add 5,000 emails to your MailKit balance instantly.- プロダクトタイプとしてSingle Paymentを選択します
- 料金を設定します。
9.00Currency: USDAttach the credit grant
- Credit Entitlement:
Email Credits - Credits issued:
5000
Step 3:バックエンドをセットアップする
チェックアウト、送信、残高取得、webhookを処理するExpressサーバーを構築します。Initialize the project
package.jsonにdev scriptを追加します。Configure environment variables
.envを作成します。DODO_WEBHOOK_KEYは、endpointを作成した後のStep 4で入力します。Resend API keyはresend.com/api-keysから取得できます。Build the server
server.tsを作成します。Add a demo UI
public/index.htmlを作成します。Step 4:Webhook endpointを接続する
credit.balance_lowイベントにより、顧客がクレジットを使い切る前に通知できます。これがなければ、問題に気づくのはメール送信に失敗したときが初めてになります。
Expose your local server
https://1234abcd.ngrok-free.app)をコピーします。Register the endpoint in Dodo
- Developers → Webhooks → Add Endpointに移動します
- URL:
https://1234abcd.ngrok-free.app/webhooks/dodo - Events:
credit.added、credit.balance_low、credit.rolled_overをsubscribeします - 保存し、signing keyを
DODO_WEBHOOK_KEYとして.envにコピーします - サーバーを再起動します
Step 5:フロー全体をテストする
Start the server
MailKit running on http://localhost:3000が表示されます。ブラウザで開いてください。Subscribe a test customer
- セクション1でテスト用メールアドレスと名前を入力し、Get checkout linkをクリックします
- リンクを開き、test cardでチェックアウトを完了します
- 支払い後、ダッシュボードのCustomersで
customer_idを確認します。
Send a real email
customer_idをセクション3に貼り付けますtoはdelivered@resend.devのままにします(すべてを受け付けるResendのsandbox inboxです)- Sendをクリックします
Trigger the low-balance webhook
- Customers → [Customer] → Credits → Email Creditsに移動します
- Adjust Balanceをクリックし、
4000をdebitします - デモからもう1通メールを送信します
Buy a top-up pack
customer_idをセクション4に貼り付けます- Buy 5,000 emailsをクリックし、test checkoutを完了します
- 残高を更新すると、5,000増加します
grant_source: one_timeを伴うcredit.addedイベントが発生します。トップアップはサブスクリプションクレジットに積み上げられ、両方のプールはFIFO(期限切れでない最古のgrantが最初)で消費されます。Test the hard stop
トラブルシューティング
Webhook signature verification fails (401)
Webhook signature verification fails (401)
express.json()はpayloadをparseして再シリアライズするため、HMACが壊れます。app.use(express.json())行より上で/webhooks/dodoがexpress.raw({ type: 'application/json' })に登録されていること、およびDODO_WEBHOOK_KEYがendpoint detail pageに表示されるsigning keyと一致することを確認してください。Balance is 0, customer not found, or credits don't deduct
Balance is 0, customer not found, or credits don't deduct
- 顧客がcheckoutを完了したこと(クレジットはsession creation時ではなく、支払い成功時に付与されます)
.env内のCREDIT_ENTITLEMENT_IDが、プロダクトに関連付けられたクレジットと一致すること(IDが一致しない場合、誤ったクレジットに書き込まれても通知されません)- 渡している
customer_idがDodo(ダッシュボードのcustomerstable)から取得したものであり、独自のdatabaseからではないこと
Resend rejects the recipient
Resend rejects the recipient
onboarding@resend.devは、Resendアカウントのメールアドレスまたはdelivered@resend.devにのみ配信します。他の宛先へ送信するには、ドメインをverifyし、そのドメインのfromアドレスを使用してください。構築したもの
One reusable credit unit
Email Creditsを1回定義し、サブスクリプションプランとトップアップパックの両方に関連付けました。Subscription with prepaid allowance
Top-up pack
Instant ledger debits
createLedgerEntryを1回呼び出します。meterもaggregation lagもなく、Resendのmessage idによってretry時もidempotentです。