$/transactional-email-api providers ↗
guide

Email Webhooks

Email webhooks turn provider-side delivery events into application state. A good endpoint verifies the signature, acknowledges quickly, stores an immutable event record, and processes the business effect from a queue. The goal is not to do everything in the request handler. The goal is to never lose or double-apply an event.

last updated 2026-08-25 4 sections
section 01

Webhook payload structure

Most providers send a message identifier, event type, recipient, timestamp, and provider-specific metadata. Some send one event per request. Others batch several events into one payload. Normalize the incoming shape before downstream systems depend on it.

fieldwhy it mattersstorage rule
provider_event_idDedupes retries and replayed callbacks.Unique index when available.
message_idConnects delivery state to the original send.Store with the outbound send row.
event_typeRoutes bounce, complaint, delivery, open, and click events.Normalize to internal enum.
raw_payloadKeeps audit data for provider disputes.Store before processing.
section 02

Signature verification

Verify the signature before parsing business meaning from the payload. Different providers sign different material: raw body, timestamp plus body, or provider-specific fields. The endpoint should reject stale timestamps and never rebuild the signed body from parsed JSON.

  • ok Read the raw request body before JSON parsing.
  • ok Verify timestamp tolerance when the provider includes one.
  • ok Compare signatures with a constant-time function.
  • ok Keep test-mode secrets separate from production secrets.
  • ok Log rejected signatures without storing sensitive payload fields.
section 03

Acknowledgment and retry behavior

Return a 2xx response after the event is authenticated and stored. Heavy work belongs in a queue. Providers retry failed callbacks, which means the endpoint must tolerate duplicate delivery and out-of-order arrival.

eventcommon actionidempotency need
deliveredMark message as accepted by the mailbox provider.Do not move a bounced message back to delivered.
hard_bounceSuppress the address for future sends.Apply once per recipient and stream.
complaintSuppress and flag reputation risk.Treat as terminal.
open or clickRecord engagement signal if tracking is enabled.Dedup high-volume repeats.
section 04

Processing and storage pattern

The safest pattern is receive, verify, store, enqueue, acknowledge. A worker can then apply state transitions, update suppression lists, notify support, or sync analytics without keeping the provider waiting.

  • ok Persist raw payload and normalized fields in the same transaction.
  • ok Use a unique event key to make replay harmless.
  • ok Process terminal states such as hard bounce and complaint before engagement states.
  • ok Alert when webhook volume drops to zero for an active stream.

reading this as teams choosing a transactional API

Judged purely as an API. What the request contract guarantees on retry, how complete the webhook event coverage is, whether suppressions are readable and writable programmatically, and how much the message log retains when something needs debugging in production.

Applied to email webhooks, that means weighing idempotency keys, webhook coverage, event stream, and operating track record ahead of the rest, against high-frequency programmatic sends where a missed delivery is a product failure.

related pages