Skip to main content

What is a webhook?

A webhook is an HTTP request sent by MailChannels when certain events in the email delivery process occur. By leveraging these events, you gain real-time insights into email delivery status, improve deliverability, and enhance your email sending strategies.

Webhook management

MailChannels provides tools to create, retrieve, delete, and validate webhooks. The first step to receiving webhooks is to create a webhook.

Creating a webhook

There are two ways to create a webhook: visit the webhooks page and click Create Webhook, or use the API. To create a webhook via the API, see the code examples below.

Event notification format

Once configured, MailChannels will send event notifications to your webhook in the following format:

Event fields

All event notifications include these common fields:
  • email: The sender’s From address.
  • customer_handle: Your MailChannels account ID. Visible in the upper-right corner of the Console.
  • timestamp: Unix timestamp of when the event occurred.
  • event: Event type, such as processed, delivered, or hard-bounced.
  • request_id: A unique identifier generated to track the original HTTP request.
The customer_handle field lets a single webhook receiver handle events for multiple accounts. This is useful if you have sub-accounts and want a single webhook receiver for all of them.
Some event types include additional fields. For the full list, see event types. For operational guidance on failed webhook deliveries and replaying batches, see webhook retries and delivery behavior. For an investigation workflow that starts from a sent message, see debug a sent message.
It is important to make sure your webhook receiver can handle up to 1,000 items in each request body. Some libraries may have default limits on the JSON body size or array length. Be sure to adjust those settings if necessary.

Retrieving webhook configuration

To view your current webhook configuration:
A successful call returns 200 OK with a JSON array of enrolled webhook endpoints. At this time, only one webhook can be configured per account.

Deleting a webhook

To stop receiving event notifications:
A successful call returns 204 No Content with an empty body.

Validating webhook configuration

To verify your current webhook setup, send a test event to each enrolled webhook:
The response reports whether each webhook returned a 2xx status code:
A test event message will be sent to your webhook containing the following fields:
  • email: “test@mailchannels.com”.
  • customer_handle: Your account ID.
  • timestamp: Unix timestamp of the test event.
  • event: “test”.
  • request_id: Either provided by you or generated automatically.
  • smtp_id: Generated automatically.

Best practices

  1. Verify the message signature.
  2. Ensure your webhook endpoint can handle concurrent requests.
  3. Process events asynchronously to avoid blocking the webhook receiver.
  4. Implement retry logic in case of temporary failures.
  5. Store raw event data before processing to allow for reprocessing if needed.

Storing webhook data

Treat webhook storage as part of your email system, not as an afterthought. A durable event table lets you answer support questions, rebuild derived state, and satisfy audit requirements. At minimum, store:
  • The full raw JSON payload.
  • The event type.
  • The event timestamp.
  • The customer_handle.
  • The request_id and smtp_id, when present.
  • Your processing status, such as received, processed, or failed.
A common pattern is to acknowledge the webhook quickly, enqueue the raw event for background processing, and update the processing status after your worker finishes.
Plan your retention period intentionally. Operational debugging may only need recent events, while compliance or customer support workflows may require longer retention.

Verifying message signatures

All webhooks are signed by default. There are three HTTP headers to consider during the signature verification process:
  • Content-Digest: hash of the message body
  • Signature-Input: describes what parts of the message are signed, along with other data about the signing method
  • Signature: the cryptographic signature

How to verify a message

1

Parse the Signature-Input header

The Signature-Input header describes how the request was signed and which parts of it were covered. For example:
From this header you can extract:
  • Signature namesig_1738775282. The matching entry in the Signature header uses the same name.
  • Covered components("content-digest"). Only the Content-Digest header was signed.
  • Created1738868393, a Unix timestamp.
  • Algorithmed25519.
  • Key IDmckey. Identifies which public key to use for verification.
2

Check the created timestamp

Reject signatures that are older than a short window (five minutes is a reasonable default) to defend against replay attacks.
3

Retrieve the public key

Fetch the public key from MailChannels using the keyid from step 1:
Cache the response and reuse it for subsequent requests. You only need to refetch when you see a keyid you haven’t encountered before.
4

Reconstruct the signing string

Rebuild the exact byte string that MailChannels signed, following the algorithm in RFC 9421, Section 2.5. For our example, the signing string is:
The rules are:
  • For each covered component, write the lowercased name in quotes, then : , then the header value, on a single line.
  • Append a final "@signature-params" line with the parenthesised component list followed by the remaining Signature-Input parameters.
  • Join lines with a single \n and do not include a trailing newline.
Use an HTTP Message Signatures library that implements RFC 9421 rather than building this string by hand. Small deviations (whitespace, header casing, trailing newlines) cause verification to fail silently.
5

Verify the signature

The Signature header carries each signature as <name>=:<base64-value>:. For example:
Base64-decode the value between the colons, then verify the resulting bytes against the signing string from step 4 using the public key and the ed25519 algorithm.

Example signature verification code