resend.emails.sendを、SendGrid、Postmark、Amazon SES、または独自のSMTPリレーへの呼び出しに置き換えてください。- ダッシュボードでメール用のカスタムクレジットentitlementを作成する。
- サブスクリプションプランと一回限りの追加購入プロダクトにクレジットを関連付ける。
- Resend経由でメールを送信し、送信ごとに1クレジットをデビットしてledgerエントリを作成する。
- フロントエンドから顧客の現在のクレジット残高を読み取る。
- Dodo Paymentsのwebhookを検証し、残高がゼロになる前に顧客へ警告する
credit.balance_lowを処理する。
構築するもの
MailKitでは2つのプロダクトを販売します。- Dodo Paymentsアカウント。すべてテストモードで構築します。
- 無料のResendアカウントとAPIキー。
- Node.js 22以降、およびTypeScriptの基本的な知識。
Step 1: メールクレジットentitlementを作成する
クレジットentitlementでは、MailKitが販売する単位、つまりメール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 UnitUnit Name: emailDefine Precision: 0。メールは整数単位なので、残高に小数は必要ありません。Credit Expiry: 30 days。未使用のクレジットは発行から30日後に期限切れになります。Leave the Other Defaults
Save and Copy the Credit ID
cde_で始まるIDをコピーします。バックエンドでは、残高の読み取りとledgerエントリにこのIDを使用します。Email Credits entitlementの準備ができました。次に、顧客へ付与するプロダクトを作成します。Step 2: プランと追加購入パックを作成する
同じEmail Credits entitlementを関連付けた2つのプロダクトを作成します。1請求サイクルごとに5,000通を付与するSubscriptionプランと、必要に応じてさらに5,000通を追加するOne Timeの追加購入プロダクトです。
MailKit Plan ($19/月、5,000通)
Create the Subscription
- Productsに移動し、Add Productをクリックします。
- プロダクトの詳細を入力します。
MailKit PlanDescription: 5,000 transactional emails per month.- Pricing TypeでSubscriptionを選択します。
- 継続価格を設定します。
19.00Repeat payment every: 1 monthCurrency: USDAttach the Email Credit Entitlement
Email CreditsCredits issued per billing cycle: 5000Low Balance Threshold (%): 20。残高が1請求サイクルあたりに発行されたクレジットの20%未満、つまり1,000通未満になると、Dodo Paymentsはcredit.balance_lowを送信します。Import Default Credit Settings: オン。これにより、プロダクトではStep 1で設定した30日間の有効期限が使用されます。クレジットをプロダクトに追加してから、プロダクトを保存します。pdt_で始まるプロダクトIDをコピーします。Top-Up Pack ($9、一回限り、5,000通)
Create a One-Time Product
- Productsに移動し、Add Productをクリックします。
- プロダクトの詳細を入力します。
Email Top-Up PackDescription: Add 5,000 emails to your MailKit balance.- Pricing TypeでOne Timeを選択します。
- 価格を設定します。
9.00Currency: USDAttach the Credit Grant
- Select credits:
Email Credits - No of credits issued:
5000
Step 3: バックエンドを設定する
チェックアウトの作成、メール送信、残高の読み取り、webhookの受信を行うExpressサーバーを構築します。Initialize the Project
package.jsonにdevスクリプトを追加します。Configure Environment Variables
.envを作成します。DODO_PAYMENTS_WEBHOOK_KEYを入力します。Resend APIキーはresend.com/api-keysで作成します。Build the Server
server.tsを作成します。サーバーでは、サブスクライブチェックアウト、追加購入チェックアウト、残高の読み取り、送信、webhook受信の5つのrouteを公開します。Add a Demo UI
public/index.htmlを作成します。各routeを簡単なフォームから呼び出すため、ブラウザでフローをテストできます。Step 4: Webhook endpointを接続する
credit.balance_lowイベントを使うと、顧客のクレジットがなくなる前に警告できます。これがない場合、顧客が問題に気付くのは、メール送信に失敗してからです。
Expose Your Local Server
https://1234abcd.ngrok-free.app。Register the Endpoint in Dodo Payments
- Developer → Webhooksに移動し、Add endpointをクリックします。
- 自分のtunnel hostを使って、URL
https://1234abcd.ngrok-free.app/webhooks/dodoを入力します。 credit.added、credit.balance_low、credit.rolled_overイベントを選択します。- Create endpointをクリックします。
- endpointのOverviewタブからsigning secretをコピーし、
.envのDODO_PAYMENTS_WEBHOOK_KEYとして入力します。 - サーバーを再起動します。
Step 5: フロー全体をテストする
Start the Server
MailKit running on http://localhost:3000が記録されます。そのURLをブラウザで開きます。Subscribe a Test Customer
- セクション1でテスト用メールアドレスと名前を入力し、Get checkout linkをクリックします。
- リンクを開き、test cardでチェックアウトを完了します。
- ダッシュボードでCustomersに移動し、
cus_で始まる新しい顧客のIDをコピーします。
Send an Email
- セクション3に顧客IDを貼り付けます。
- Toは
delivered@resend.devのままにします。これはすべてのメッセージを受け付けるResendのテストアドレスです。 - Sendをクリックします。
Trigger the Low-Balance Webhook
- Customersで顧客を開き、Creditsタブを選択して、Email Creditsを選びます。
- Apply Credit/Debitをクリックし、Debitを選択して、
4000を入力します。残高はちょうど1,000になりますが、まだしきい値未満ではありません。 - デモからもう1通メールを送信します。残高は999になります。
Buy a Top-Up Pack
- セクション4に顧客IDを貼り付けます。
- Buy 5,000 emailsをクリックし、テストチェックアウトを完了します。
- 残高を更新します。5,000増加しています。
transaction_type: "credit_added"を含むcredit.addedイベントを送信します。その背後にあるgrantにはsource_type: one_timeがあります。これはList Customer Grants APIで読み取れます。追加購入クレジットはサブスクリプションクレジットに加算されます。デビットは最初に期限切れになるgrantから、同時に期限切れになる場合は最も古いgrantから消費されます。Test the Hard Stop
402を返します。402は、アプリケーションによる制御です。Dodo Paymentsの残高APIをsource of truthとして扱い、クライアント側で残高をキャッシュしないでください。トラブルシューティング
Webhook signature verification fails (401)
Webhook signature verification fails (401)
express.json()はbodyを解析済みオブジェクトに置き換えるため、検証に失敗します。/webhooks/dodoをexpress.raw({ type: 'application/json' })とともに、app.use(express.json())行より上で登録します。次に、DODO_PAYMENTS_WEBHOOK_KEYがendpointのOverviewタブにあるsigning secretと一致することを確認します。Balance is 0, customer not found, or credits don't deduct
Balance is 0, customer not found, or credits don't deduct
- 顧客がcheckoutを完了していること。クレジットはcheckout sessionの作成時ではなく、支払いが成功したときに発行されます。
.env内のCREDIT_ENTITLEMENT_IDが、プロダクトに関連付けられたクレジットと一致していること。残高とledgerの呼び出しではこのIDを使用するため、一致しないと別のクレジットを読み取ったりデビットしたりします。- 渡している
customer_idがDodo Paymentsの顧客IDであること。cus_で始まるIDであり、自分のデータベースのIDではありません。
Resend rejects the recipient
Resend rejects the recipient
onboarding@resend.devは、Resendアカウントのメールアドレス、またはdelivered@resend.devにのみ配信します。他の宛先に送信するには、ドメインを検証し、そのドメインのfromアドレスを使用します。構築したもの
One Reusable Credit Unit
Email Creditsを1回定義し、サブスクリプションプランと追加購入パックの両方に関連付けました。Subscription with Prepaid Allowance
Top-Up Pack
Direct Ledger Debits
createLedgerEntryを1回呼び出します。meterも集計の遅延もありません。Resend message IDをidempotency keyとして使用することで、同じ送信に対する2回目のデビットを防止します。