Email Webhooks Explained: How to Handle Delivery Events in Real Time

When you send transactional email — a password reset, an order confirmation, a notification — you need to know what happened to it. Did it deliver? Did it bounce? Was it opened? Polling an API endpoint every few seconds for status isn't practical at scale. Email webhooks solve this by pushing delivery events to your server the moment they happen.
Webhooks are one of the most useful tools in a transactional email integration, and one of the most commonly underused. This guide explains how they work, what events to handle, and how to build a reliable webhook receiver.
What Is an Email Webhook?
An email webhook is an HTTP POST request sent by your email provider to a URL you specify, containing data about something that happened to one of your messages. When a message is delivered, the provider posts a JSON payload to your endpoint. When it bounces, same thing. Opens, clicks, unsubscribes, spam complaints — each can trigger its own webhook event in near real time.
The flow looks like this:
- You send a transactional email through your provider's API or SMTP relay
- Something happens — delivery, bounce, open, click
- Your provider sends an HTTP POST to your webhook URL with event data
- Your server processes the event and updates your database or triggers application logic
Instead of your application asking "what happened to this message?", the provider tells you as soon as something happens. This is event-driven design applied to email delivery.
Common Webhook Event Types
Delivered
Fires when the receiving server accepted the message. This confirms the message left your provider and was accepted for delivery — but doesn't guarantee inbox placement. The message could still be filtered to spam at the recipient's mail server.
Bounce
Bounces come in two types, and your webhook payload should tell you which one occurred:
- Hard bounce: Permanent failure — invalid address, domain doesn't exist. Remove this address from your list immediately and never retry it.
- Soft bounce: Temporary failure — mailbox full, server temporarily unavailable. You can retry soft bounces, but track them over time. Repeated soft bounces on the same address often indicate a dead mailbox.
Handling bounces via webhook is the right way to maintain suppression lists. When a hard bounce webhook fires, add that address to your suppression list before the next campaign goes out.
Complaint / Spam Report
Fires when a recipient marks your message as spam. Most major providers feed these back through feedback loops (FBLs), which your email provider aggregates and delivers as webhook events. A complaint should immediately suppress the recipient's address — continuing to send to someone who has complained is both a deliverability risk and a compliance problem in most jurisdictions.
Open
Fires when the recipient opens the message, tracked via a 1×1 pixel image in the HTML body. Note that Apple's Mail Privacy Protection preloads email content and fires open events even when the recipient hasn't actually opened the message. On lists with significant Apple Mail users, treat open data as directional rather than precise.
Click
Fires when the recipient clicks a tracked link. Your provider wraps links with redirect URLs; when the recipient clicks, the redirect fires the webhook before forwarding them to the destination. Click tracking is considerably more reliable than open tracking as an engagement signal.
Unsubscribe
Fires when the recipient clicks an unsubscribe link. Your webhook receiver should immediately update your list to reflect this preference. Never batch-process unsubscribes — the legal and deliverability risks of delays are real. See our guide on managing unsubscribe requests correctly.
Building a Reliable Webhook Receiver
Acknowledge Fast, Process Asynchronously
Your webhook endpoint must return a 200 HTTP status quickly — typically within 5–10 seconds. Most providers will retry the webhook if they don't receive a 200 response, creating duplicate events. Acknowledge the request immediately, push the payload to a queue, and process it asynchronously:
// Express.js example
app.post('/webhooks/email', (req, res) => {
res.status(200).send('OK'); // Acknowledge immediately
queue.push(req.body); // Process in the background
});
Verify Webhook Signatures
Anyone who discovers your webhook URL can POST to it. Verify that incoming requests are actually from your email provider by checking the webhook signature. Providers typically include an HMAC signature in a request header, computed using a shared secret. Reject requests where the computed signature doesn't match the one in the header.
Handle Duplicates Idempotently
Webhook providers can deliver the same event more than once — especially during network instability or provider retry logic. Your handler should be idempotent: processing the same event twice should produce the same result as processing it once. Use the event's unique ID to deduplicate before making any database changes.
Log Everything Before Processing
Store every incoming webhook payload, including the timestamp and event type, before you process it. If something goes wrong with your processing logic, you'll want the raw events available to replay. A simple append-only log of raw payloads is a low-cost insurance policy.
What to Do With Webhook Data
The most actionable webhook events for most transactional email applications:
- Hard bounces → suppress address immediately
- Complaints → suppress address immediately
- Soft bounces → track count; suppress after a defined threshold
- Clicks → update engagement score, trigger follow-up workflows
- Unsubscribes → update preference record in real time
Combining bounce and complaint data from webhooks is how you build a self-maintaining suppression list. Every send automatically updates your list health without manual intervention. For more on this, see our guide on bounce management and suppression lists.
Webhooks vs Polling
The alternative to webhooks is polling: calling your provider's API periodically to check the status of sent messages. Polling works at low volume but becomes expensive and slow as you scale. Webhooks are push-based and near real-time — the right architecture for any application that needs to act on delivery events promptly and maintain accurate list state.
For transactional email infrastructure built around reliable event delivery, see MailDog's SMTP relay and the documentation for webhook configuration specifics. For broader context on building a transactional email integration, read our guide on email API integration.
Start With Bounces and Complaints
If you're new to webhooks, start with the two events that matter most for deliverability: hard bounces and spam complaints. Wire those up first, suppress addresses immediately when either fires, and you'll eliminate the most common cause of sender reputation damage. Add open and click tracking once the fundamentals are solid.


