C#
Webhook の検証
配信の内容を信頼する前に、その署名を確認します。
配信を検証する
using OpenEmail; var builder = WebApplication.CreateBuilder(args);var app = builder.Build();var secret = builder.Configuration["OPENEMAIL_WEBHOOK_SECRET"] ?? string.Empty; app.MapPost("/webhooks/openemail", async (HttpRequest request) =>{ using var reader = new StreamReader(request.Body); var payload = await reader.ReadToEndAsync(); try { var delivery = OpenEmailClient.VerifyWebhookSignature(payload, request.Headers["X-OpenEmail-Signature"], secret); app.Logger.LogInformation("{Type} {Id}", (string?)delivery["type"], (string?)delivery["id"]); return Results.NoContent(); } catch (OpenEmailWebhookException) { return Results.BadRequest(); }}); app.Run();OpenEmailClient.VerifyWebhookSignature() は、タイムスタンプとボディに対するヘッダーの HMAC を定数時間で確認し、イベントを JsonObject として返します。2 番目の引数は X-OpenEmail-Signature ヘッダーの値で、リクエストヘッダーそのものを受け取るオーバーロードもあります。シークレットは client.Webhooks.CreateAsync() が返したものです。
届いたままの生のボディを渡してください。解析して再エンコードしたボディは、もう署名と一致しません。
古い配信
var payload = """{"id":"evt_1","type":"email.received"}"""; try{ OpenEmailClient.VerifyWebhookSignature(payload, "t=1767225600,v1=5f2d", "whsec_example", toleranceSeconds: 60);}catch (OpenEmailWebhookException error){ Console.WriteLine($"refused: {error.Message}");}5 分以上前の配信は拒否されるため、傍受されたリクエストをあとで再送することはできません。toleranceSeconds: でこの 5 分を変更でき、ゼロにするとどれだけ古い配信でも受け付けます。
- ヘッダーがない場合や形式が正しくない場合、署名が一致しない場合、配信が古すぎる場合は、いずれも
OpenEmailWebhookExceptionがスローされます。 - シークレットをローテーションしたあとは、配信に複数の署名が付くことがあり、どれか 1 つが一致すれば通ります。
- すばやく 2xx のステータスで応答してください。それ以外の応答を受けた配信は、あとで再試行されます。