すべての記事
Mailgun Webhookをlocalhostでテストする方法
Mailgunemail webhooksHMAC verificationlocalhost

Mailgun Webhookをlocalhostでテストする方法

localhostでMailgun Webhooksをテストするには、ローカルハンドラをexpose npx portpreview PORT, 必要なMailgunイベントタイプで結果のHTTPSエンドポイントを設定し、イベントを受け入れる前にペイロードのタイムスタンプ、トークン、およびHMAC-SHA256署名を確認します。

新着情報メールガンwebhooks レポート

Mailgun 設定されたイベントが発生したときに HTTP または HTTPS POST を JSON ペイロードで送信します。 現在のイベントの種類には、 accepted, delivered, temporary_fail, permanent_fail, opened, clicked、スパムの苦情および退会。 トラッキングに依存しないイベントは、対応するトラッキングが有効になっている場合にのみ表示されます。

現在の Mailgun Send webhook ボディは、 signature オブジェクト event-data. イベントデータには、次のようなフィールドが含まれます。 event, id, timestampイベントの種類に応じて、メッセージヘッダー、受信情報、タグ、および配信の詳細。 文書化されたフィールドに対するコードと、不在なオプションのプロパティを許容します。 Mailgunの公式 ペイロード例 契約テストに最適な備品です。

Mailgun Send webhook を Mailgun と混同しないでください。 アラート アラートは、さまざまな署名キーを使用して、POST 本体全体を POST ボディ全体に署名します。 X-Sign ヘッダー。 このガイドは、ペイロードとアカウントのWebhook Signing KeyのシグネチャフィールドをWebhooksに送信します。

1. ローカル Mailgun エンドポイントを構築する

生の JSON ボディに署名するスキームとは異なり、 Mailgun Send の文書化された計算は、署名オブジェクトのタイムスタンプとトークンを使用します。 そのため、JSON の標準解析が適切です。 以下の Express ハンドラは HMAC を検証し、再生年齢チェックを実行し、イベントを 確実に受け入れます。

import crypto from 'node:crypto';
import express from 'express';

const app = express();
app.use(express.json({ limit: '1mb' }));

function verifyMailgunSignature({ timestamp, token, signature }) {
  if (!timestamp || !token || !signature) return false;

  const expected = crypto
    .createHmac('sha256', process.env.MAILGUN_WEBHOOK_SIGNING_KEY)
    .update(String(timestamp) + String(token))
    .digest('hex');

  const expectedBytes = Buffer.from(expected, 'hex');
  const actualBytes = Buffer.from(String(signature), 'hex');
  return expectedBytes.length === actualBytes.length &&
    crypto.timingSafeEqual(expectedBytes, actualBytes);
}

app.post('/webhooks/mailgun', async (req, res) => {
  const signing = req.body?.signature;
  const event = req.body?.['event-data'];

  if (!signing || !event || !verifyMailgunSignature(signing)) {
    return res.status(406).send('invalid webhook');
  }

  const ageSeconds = Math.abs(Date.now() / 1000 - Number(signing.timestamp));
  if (!Number.isFinite(ageSeconds) || ageSeconds > 15 * 60) {
    return res.status(406).send('stale webhook');
  }

  await acceptOnce({
    eventId: event.id,
    replayToken: signing.token,
    payload: event,
  });
  return res.sendStatus(200);
});

app.listen(3000);

15分ウィンドウは、 Mailgun で管理された値ではなく、アプリケーションポリシーです。 Mailgun は、タイムスタンプが現在の時刻から遠くないことを確認することをお勧めしますが、配達が遅れる可能性があるため、攻撃的であることに警告します。 キューイングとインシデント回復の要件に合ったウィンドウを選択し、正当な拒絶を監視し、意図的に調整します。

Webhook Signing Key を秘密のマネージャーや環境変数に格納し、ソース制御では行いません。 Mailgun の Webhooksガイドの確保 正確な計算を定義します。: 分離器のないタイムスタンプとトークンを連結し、Webhook Signing Key を使用して HMAC-SHA256 を計算し、ヘキサデシマル消化と比較します。 signatureお問い合わせ

2. HTTPS上でローカルホストを露出

ポート3000で聴くアプリケーションで、実行します。

npx portpreview 3000

ローカルルートをパブリックHTTPSの起源に追加します。 例えば:

https://example.portpreview.dev/webhooks/mailgun

試験中のアプリケーションとトンネルを両方残します。 Mailgun 一般に到達可能な URL が必要です。 localhost、プライベートなLANアドレス、および自己署名された開発証明書は、遠隔地には適していません。 PortPreview は、パブリック HTTPS を終了し、ローカルポートへのリクエストを転送します。

3. Mailgun イベントURLの設定

Mailgun は、アカウントレベルとドメインレベルの Webhook 設定をサポートしています。 アカウントレベルのエンドポイントは、ドメイン間でイベントを受信し、サブアカウントを継承することができます。ドメインレベルのエンドポイントは、そのドメインにのみ適用されます。 各イベントタイプを個別に設定し、3つのURLまで設定できます。 アプリケーションにマッチする最も狭いスコープを選択します。

  1. 意図したアカウントまたは送信ドメインのWebhooksエリアを開きます。
  2. イベントの種類を選択します。 delivered または permanent_failお問い合わせ
  3. 完全なPortPreview HTTPSエンドポイントを追加します。
  4. ハンドラがサポートするイベントごとに繰り返します。
  5. テストや実際のメッセージを送信し、ローカルリクエストとアプリケーションログを検査します。

Mailgun は、同じイベントの URL を、アカウントとドメインの両方で設定するが、それぞれ異なる URL がコピーを受け取ることができます。 親アカウントの相続も、複数の異なるエンドポイントへの配送を引き起こす可能性があります。 公式レビュー 設定ルール 配送先を配送先へ引き渡す前に。

Mailgun 署名検証の仕組み

ザ・オブ・ザ・ signature オブジェクトには:

  • timestamp: 秒単位でUnixの時間。
  • token: ランダムに生成された50文字の文字列。
  • signature: hexadecimal HMAC 消化器。
  • parent-signature: オプションでサブアカウントからイベントを提示し、 Mailgun で説明したプライマリアカウントのリレーションに対して検証ができます。

通常のアカウント署名のために、計算します HMAC-SHA256(signingKey, timestamp + token). 分離器と event-data JSON は、この文書の Mailgun Send 計算の一部ではありません。 同一の長さを点検した後のタイミングの安全な機能のデコードされたバイトを比較して下さい。 プレーン === 比較は簡単ですが、タイミングセーフな比較は、より安全な生産デフォルトです。

本物のHMACは、署名鍵を握るパーティーがシグネチャを生成したことを証明しています。 この配送が再生されていないことを証明しません。 Mailgun 具体的には、トークンをキャッシュし、同じトークンでその後のリクエストを拒否することを推奨します。 タイムスタンプ率チェックは、キャプチャされた有効リクエストの有効期間がどれだけ有効であるかを制限します。 両方のコントロールを使用する:再生のためのユニークなトークン制約と鮮度のための合理的な時間ウィンドウ。

配送と効果の両方の重複

2つの耐久性のあるユニークネス制約を保ちましょう:署名トークンとMailgunの1つ event-data.id. トークンは同一の署名された配達再生を捕獲します。 イベント ID は、同じイベントが別の有効な配信コンテキストに表示されている場合、ビジネス ロジックを保護します。 プロバイダーとアカウントまたは環境の両方で名前空間。

async function acceptOnce({ eventId, replayToken, payload }) {
  await db.transaction(async (tx) => {
    const tokenWasNew = await tx.webhookTokens.insertIfAbsent({
      provider: 'mailgun',
      token: replayToken,
    });
    if (!tokenWasNew) return;

    const eventWasNew = await tx.webhookEvents.insertIfAbsent({
      provider: 'mailgun',
      eventId,
      receivedAt: new Date(),
    });
    if (!eventWasNew) return;

    await tx.jobs.enqueue({
      type: 'process-mailgun-event',
      payload,
    });
  });
}

データベース固有のインデックスを使用して、インサート・イフ・アベント・オペレーションをバックアップします。 リードの続行は、同時配信中のレース・プロンです。 バックアップレコードをコミットし、ジョブの原始をキューに入れます。 ワーカーの更新メッセージの状態を素早く確認し、アラートをトリガーしたり、CRMを同期させる。 詳細はこちら 再試行と出没ガイド キューとビジネスデータベースがトランザクションを共有できないときの代わりに。

Mailgun 応答コードとリトライ動作

Mailgun の現在の Webhook ドキュメントの送信は 3 つの重要な結果をもたらします。

  • 200 成功: Mailgun Webhook POSTを成功に扱い、再試行しません。
  • 406 受け入れられない: Mailgun POSTを拒絶し、再試行しません。
  • 他のコード: 配送通知以外のWebhookの場合、メールガン5分、10分、15分、1時間、2時間、4時間で8時間以上遅れます。

デリバリー通知例外事項:すべてのイベントタイプが一般的なリトライスケジュールに従うことを約束しません。 最新情報を見る 自動検索文書 配達保証があなたの設計に影響を与えるとき。

406 は、無効なシグネチャや外部ポリシーなどの永続的に拒否するリクエストのみに使用します。 一時的なデータベースとキューの失敗のために500または503を使用して、資格のあるWebhookタイプを再試すことができます。 耐久の受け入れの後でだけ200を戻して下さい。 未追跡のバックグラウンドワークを開始しながら200を返すと、プロセス終了時にイベントを失うことができます。

トラブルシューティング Mailgun webhooks ローカル

計算されたHMACは決してマッチしません

ご使用のメールアドレスを入力してください。 Webhook Signing KeyAPI キー、SMTP パスワード、またはキー署名のアラートではありません。 署名オブジェクトのタイムスタンプとトークンを区切りにし、区切り無しにします。 より低い箱の hexadecimal SHA-256 の消化器を作り出す。 また、フレームワークがハイフン化されていないことを検証します event-data プロパティ;ブラケットの表記は間違いを避けます。

ハンドラは、現在のJSONの代わりにフォームフィールドを受け取ります

Mailgun 機能とエンドポイントバージョンがリクエストを生成するかを確認します。 従来のペイロードのチュートリアルを現在の送信Webhookに盲目に適用しないでください。 コンテンツの種類、トップレベルのフィールド名、およびメッセージ内容や秘密をログにすることなく開発中のボディ長をログにし、アカウントと統合のための文書化された契約を実行します。

Mailgun 再試行を続けます

ワイヤーに送られる実際の状態を点検して下さい。 データベースのコミット後の例外は、レスポンスを500に変え、別の試みを引き起こします。 そのため、イベントIDとトークンのインサートはユニークで耐久性のあるものでなければなりません。 リクエストが永続的に無効な場合は、406 を返します。失敗が一時的な場合は、サービスを修正し、再試行の動作を許可します。

イベントが localhost に達していない

正しいアカウントまたはドメインにURLが添付され、生成される正確なイベントタイプにURLが添付されていることを確認します。 ツイート delivered URLが届かない opened イベント ローカルのプロセスとトンネルがアクティブであり、設定されたパスが /webhooks/mailgun. フォローする ローカルWebhookデバッグガイド ルーティングとアプリケーションエラーからプロバイダの構成を分離します。

セキュリティチェックリスト

  • 信頼やロギングの前にHMACを確認 event-dataお問い合わせ
  • サインキーを秘密の店に保管し、管理された配置で回転させます。クライアント側のコードでは決して露出しません。
  • タイミングセーフなダイジェストの比較、タイムスタンプのポリシー、およびトークンの耐久性のあるユニークな制約を使用してください。
  • イベントの種類と必須フィールドを有効化する前に、イベントの種類と必須フィールドを有効化します。 受信者のアドレス、件名、保存URL、ユーザー変数を機密データとして扱います。
  • POST だけを受け入れる, 体の大きさをキャップします。, HTTPS を使用します。, 正当なブロックせずに率制限の失敗 Mailgun retries.
  • ローカル管理者やデバッグエンドポイントを一時公開の起源を通じて公開しないでください。
  • テスト終了時、一時的なURLを削除し、安定した生産エンドポイントを設定します。

Mailgun は、受信サーバーが有効な TLS を持っているとき、Webhook 要求のオプションの TLS クライアント証明書を文書化します。 トランスポートレベルのバリデーションを提供できますが、ペイロードHMAC検証、リプレイ制御、およびアプリケーション認証を交換しません。 脅威モデルに応じてレイヤーコントロール。

生産受入試験

  1. 有効な署名された据え付け品を渡し、1つの耐久でき事と200の応答を確認して下さい。
  2. 署名を変更せずにトークンを変更し、イベントの書き込みなしで406を確認します。
  3. 正確な有効なボディを再生し、第2の仕事か副作用を確認して下さい。
  4. 設定されたウィンドウの外にタイムスタンプで有効な署名を送信し、意図した拒否を確認します。
  5. 一時的なデータベースのエラーを強制し、非-200/non-406応答を確認し、データベースを復元し、成功した受け入れを検証します。
  6. ペイロードフィールドと再試行の期待が異なるため、各設定されたMailgunイベントタイプを練習します。

これらのテストが通過したら、同じ検証と生産の重複パスを使用します。 HMAC比較と秘密処理のプロバイダーに依存しない説明については、 webhook 署名検証ガイドお問い合わせ

よくある質問

できますメールガンwebhook を localhost に送信しますか?
Mailgun ローカルホストに直接アクセスできません。 `npx portpreview PORT` を実行し、生成された HTTPS のソースに webhook ルートを追加し、必要な Mailgun イベントタイプごとにパブリック URL を設定します。
Mailgun Send Webhook 署名を検証するにはどうすればよいですか?
分離器のないペイロード署名オブジェクトのタイムスタンプとトークンを連結し、 Webhook Signing Key を使用して HMAC-SHA256 ヘキサデシマルダイジェストを計算し、タイミングセーフ比較を使用して、提供されたシグネチャとそれを比較します。
Mailgun Webhookリプレイ攻撃を防ぐ方法は?
各シグネチャートークンを耐久性のあるユニークな制約下に保存し、すでに見られたトークンを拒否します。 また、合理的なタイムスタンプ率ポリシーを強制し、正当な配送遅延と運用要件の十分な時間を可能にします。
Mailgun が失敗した webhook を再試行しますか?
Mailgun 200 を成功として扱い、406 は永続的な拒絶として。 他の応答については、配信通知以外のWebhooksは、約8時間にわたって文書化された再試行間隔を使用するので、ハンドラは重要である必要があります。