オレンジ色のケーブルが接続されたパッチパネル
現場の実践

SendGrid Webhookをローカルでテストする3つの手法と署名検証の仕組み

目次を見る

外部のメール配信サービスが送ってくるWebhookイベントを、ローカル開発環境で受け取るにはどうすればよいか。この問いは、SendGrid(Twilioが提供するクラウドメール配信サービス)を使うシステムの運用監視設計において、見落とされがちな盲点のひとつです。

Webhookテストが難しい根本的な理由

Webhook(ウェブフック)とは、イベント発生時に外部サービスが指定URLへHTTP POSTリクエストを送る仕組みのことです。SendGridの場合、メールのバウンス(配信失敗)・開封・クリック・スパム報告などが発生した瞬間に、あらかじめ登録したエンドポイントへイベントデータを送信します。このデータを受け取ってDBを更新したり、アラートを発火させたりする処理が、メール運用監視の根幹を担います。

問題は、SendGridのサーバーはインターネット上にあるため、開発者のローカル環境にある localhost:3000 へは直接到達できないことです。ステージング環境へコードを都度デプロイしてテストするという手段もありますが、バウンスイベントの再現タイミングを制御しにくく、デバッグのサイクルが著しく長くなります。

3つのアプローチとそれぞれのトレードオフ

最も手軽な方法が、ngrok(エングロック)を使ったトンネリングです。ngrokはローカルポートをインターネットに一時公開するツールで、発行されるURLをSendGridのWebhook設定に登録するだけで動作します。しかし、ngrokを再起動するたびにURLが変わるため、SendGrid側の設定を都度更新しなければなりません。複数の開発者が同時に作業する環境では管理が煩雑になります。

2つ目のアプローチが、Anonymily(アノニミリー)のようなWebhookリレーサービスを使う方法です。仕組みは次のとおりです。

  • Anonymilyのクラウド上に固定URLのエンドポイントが発行される
  • SendGridはその固定URLへイベントを送信する
  • AnonymilyCLIがSSE(Server-Sent Events:サーバーからクライアントへのリアルタイムストリーム技術)でローカルプロセスへイベントを転送する
  • ローカルのExpressサーバーが実際の処理を行う

固定URLが維持されるため、再起動後も追加設定は不要です。フリープランでは48時間分のペイロード履歴とシングルリプレイ(再送信)が利用でき、月額9ドルのProプランでは編集済みペイロードの再送信や署名再生成も可能になります。

3つ目は、テスト用の合成イベントを生成するアプローチです。Anonymily Proでは、実際にメールを送信しなくても、SendGridが署名したものと同等のテストイベントを生成できます。障害対応のリハーサルや、特定のバウンスコードを再現したい場合に有効です。

HMAC-SHA256署名検証を省略してはいけない理由

Webhookエンドポイントをインターネットに公開する以上、なりすましリクエストへの対策が必要です。SendGridはすべてのWebhookリクエストに署名を付与します。具体的には、x-twilio-email-timestamp ヘッダーのタイムスタンプと生のリクエストボディを連結した文字列に対し、HMAC-SHA256(ハッシュベースのメッセージ認証符号)でハッシュ値を生成し、x-twilio-email-signature ヘッダーに Base64 エンコードして付与します。

受信側はこの手順を再現し、計算したハッシュとヘッダーの値を比較することで、SendGrid以外からのリクエストを弾けます。実装上の注意点として、署名の検証にはJSONパース前の生のボディ文字列が必要です。多くのExpressミドルウェアはボディを自動でパースするため、rawBody を別途保存する処理が要ります。

app.use((req, res, next) => {
  let data = '';
  req.on('data', chunk => { data += chunk; });
  req.on('end', () => {
    req.rawBody = data;
    next();
  });
});

この生ボディ保存の処理を怠ると、署名検証が常に失敗する、あるいは検証をスキップせざるを得なくなります。後者はセキュリティ上のリスクを残すため、監視基盤の設計段階から考慮しておく必要があります。

運用監視の観点から整理すると、Webhookの受信処理には「イベントの取りこぼし検知」という側面もあります。SendGridはイベント送信に失敗した場合、一定回数リトライしますが、ローカル環境がダウンしていればそのイベントは消失します。Anonymilyのようなクラウドバッファリングサービスはこのリスクを軽減しますが、本番環境ではWebhookエンドポイント自体の可用性設計(冗長化・タイムアウト設定・キューイング)も並行して検討が必要です。

たとえばバウンスイベントを取りこぼすと、無効なメールアドレスへの送信が継続されてしまい、SendGridのドメインレピュテーション(送信者評判スコア)が低下して配信率に影響が出ます。ローカルテストの精度を高めておくことが、本番での障害予防に直結するのはこの構造からです。

Webhookのローカルテスト環境を整えることは、単なる開発の便利さの話ではありません。バウンスやスパム報告といった異常系イベントを確実に捕捉できるシステムかどうかを、本番前に検証できる唯一の手段です。

参考

How to Test SendGrid Webhooks Locally

この記事について: 本記事は AI を活用して作成し、forva AI 編集部が内容を確認・監修しています。

AI 駆動開発のご相談は forva AI へ。まずはお気軽にどうぞ。