Email Provider Webhooks: SendGrid, Mailgun & SES

Email Provider Webhooks: SendGrid, Mailgun & SES

If you are implementing email provider event webhooks for delivery tracking, bounce handling, complaints, and engagement analytics, the hard part is not receiving HTTP POST requests. The hard part is building one pipeline that is secure, idempotent, and consistent across providers with very different payload and signature models.

This guide is the pillar page for SendGrid, Mailgun, and AWS SES/SNS webhook handling in Laravel/PHP teams using SendPromptly. It gives you the architecture, normalization pattern, and security baseline, then routes you to provider-specific implementation guides.

Supporting guides in this cluster

What “good” looks like for provider webhooks

A production-safe email provider webhook integration should:

  1. Verify authenticity before business processing.
  2. Return 2xx quickly to control retries.
  3. Persist enough raw context for replay/debug.
  4. Process asynchronously with dedupe and idempotency.
  5. Normalize provider-specific events into one canonical event model.
  6. Forward canonical events into SendPromptly with an Idempotency-Key.

If any one of those six is missing, you usually get one of these incidents: duplicate side effects, spoofed notifications, hidden drops, or “we got a 2xx but nothing actually processed.”

Provider comparison at a glance

ProviderDelivery shapeAuth/signature modelKey implementation guide
SendGrid Event WebhookJSON array (batched events)Signed Event Webhook using ECDSA over timestamp + raw bytesReceive + normalize and verify signature
Mailgun WebhooksOften form-encoded (can vary)HMAC-SHA256 over timestamp+token, plus replay protectionsReceive + normalize and verify signature
AWS SES via SNSSNS envelope, nested SES payload in MessageSNS certificate-based signature validation + TopicArn controlsSES/SNS flow and verify SNS signature

Canonical architecture for email provider event webhooks

1) Receive provider webhook on a dedicated endpoint

Keep provider endpoints explicit, for example:

  • /webhooks/sendgrid/events
  • /webhooks/mailgun/events
  • /webhooks/aws/sns/ses

Dedicated routes make auth, rate controls, and observability cleaner.

2) Verify signatures in middleware (fail closed)

Run verification before parsing/mutating body content. Reject unauthorized or stale requests with 401 and no side effects.

  • SendGrid: validate signed webhook headers and raw-body signature.
  • Mailgun: validate timestamp, token, and HMAC signature with replay defense.
  • SNS: validate message signature and pin expected topic where possible.

3) ACK fast (200/204), queue heavy work

Provider webhooks are at-least-once delivery systems. If you block in request threads, you amplify retries and duplicates. Accept quickly, then enqueue processing.

4) Dedupe and idempotency before state changes

Use deterministic dedupe keys and store them before applying downstream side effects.

Recommended key ingredients:

  • SendGrid: sg_event_id + event + timestamp
  • Mailgun: provider message identity + event + timestamp/token context
  • SNS/SES: SNS MessageId + SES notification type + message identity

5) Normalize to one internal schema

Normalize all providers into one canonical event payload so analytics, alerting, and workflows are provider-agnostic.

1
2
3
4
5
6
7
8
{
  "provider": "sendgrid|mailgun|ses",
  "provider_event": "delivered|bounce|complaint|open|click|...",
  "occurred_at": 1700000000,
  "recipient": "[email protected]",
  "message_id": "provider-message-id",
  "meta": { "raw_provider_payload": "..." }
}

6) Forward to SendPromptly ingestion with idempotency

Use one canonical event key (for example email.provider_event) and always send an Idempotency-Key header so retries do not create duplicate runs.

Reference: Event Ingestion and Authentication.

Event taxonomy mapping (provider -> canonical)

Canonical typeSendGrid examplesMailgun examplesSES/SNS examples
delivereddelivereddeliveredDelivery notification
bouncebounce, droppedbouncedBounce notification
complaintspamreportcomplainedComplaint notification
deferreddeferreddelayed/temporary failure equivalentstransient delivery delays (provider-specific context)
openopenopenedtypically not SES core feedback via SNS
clickclickclickedtypically not SES core feedback via SNS

The goal is stable downstream behavior regardless of provider naming differences.

Security baseline checklist

  • Verify before queueing or persistence side effects.
  • Use raw body where provider algorithms require it.
  • Enforce timestamp drift windows and replay controls.
  • Pin trusted origins (topic ARN/cert domains where applicable).
  • Never log secrets, full tokens, or sensitive payload fields.
  • Rotate secrets/keys with staged rollout and test vectors.

Deep dive references:

Observability and debugging workflow

For email provider event webhooks, debugging should follow one order every time:

  1. Confirm provider attempted delivery.
  2. Confirm your endpoint received and verified the request.
  3. Confirm dedupe/idempotency decision.
  4. Confirm normalized event forwarding to SendPromptly.
  5. Confirm resulting run state and retries in logs.

Use these guides for deterministic troubleshooting:

  1. Implement provider endpoint + fast ACK pattern.
  2. Add signature verification and replay controls.
  3. Add dedupe store and idempotent worker behavior.
  4. Normalize events and forward into SendPromptly.
  5. Add alerting for signature failures, timeout spikes, and retry storms.

This sequence reduces integration risk and gives you production visibility early.

Conclusion

Email provider event webhooks are most reliable when you treat them as a security and reliability pipeline, not just an HTTP controller. Build once with verification, fast acknowledgment, idempotent async processing, and canonical normalization, then plug in each provider-specific adapter.

Start with the provider you use today, then follow the linked implementation + verification guides above to reach a consistent multi-provider model in SendPromptly.