Skip to content
Last updated

Webhooks

Webhooks allows you to programmatically handle events that happen with your messages sent through Mailgun. By configuring URL(s) in the Webhooks tab of the Control Panel, Mailgun can send HTTP/HTTPS POST requests to specified endpoints when certain events occur. Webhooks are configured at the domain level, enabling you to set unique endpoints for each domain via the domain drop-down selector.

Supported Webhook types:

  • Accepted, Delivered, Clicks, Spam Complaints, Unsubscribes, Permanent Failures, Temporary Failures, Spam Complaints

| Note: If you want to include an HTTPS endpoint, it must be configured with a trusted CA (Certificate Authority) signed SSL certificate, not a self-signed certificate.

You can read more about the data that is posted in the appropriate section below (Tracking Opens, Tracking Clicks, Tracking Unsubscribes, Tracking Spam Complaints, Tracking Failures, Tracking Deliveries). We recommend using http://bin.mailgun.net/ for creating temporary URLs to test and debug your webhooks. | | --- |

For Webhook POSTs, Mailgun listens for the following codes from your server and reacts accordingly:

  • If Mailgun receives a 200 (Success) code, it will determine the webhook POST is successful and not retried.
  • If Mailgun receives a 406 (Not Acceptable) code, Mailgun will determine the POST is rejected and not retry.
  • For any other code, Mailgun will retry POSTing according to the schedule below for Webhooks other than the delivery notification.

If your application is unable to process the webhook request, but you do not return a 406 error code, Mailgun will retry (other than for delivery notification) during 8 hours at the following intervals before stopping to try: 5 minutes, 10 minutes, 15 minutes, 1 hour, 2 hours, and 4 hours.

The Webhooks API endpoint allows you to programmatically manipulate the webhook URLs defines for a specific domain. See the Webhooks API for more details.

Payload

When something happens to your email, your URL will be called with application/JSON payload with the following data:

{
  “signature”:
  {
    "timestamp": "1529006854",
    "token": "a8ce0edb2dd8301dee6c2405235584e45aa91d1e9f979f3de0",
    "signature": "d2271d12299f6592d9d44cd9d250f0704e4674c30d79d07c47a66f95ce71cf55"
  }
  “event-data”:
  {
    "event": "opened",
    "timestamp": 1529006854.329574,
    "id": "DACSsAdVSeGpLid7TN03WA",
    // ...
  }
}

The 'signature' parameters are described in Securing Webhooks and the 'event-data' parameters are the same as described in Event Structure.

Securing Webhooks

To ensure the authenticity of event requests, Mailgun signs them and posts the signature alongside the webhook's event-data.

A signature takes the following form:

ParameterTypeDescription
timestampintNumber of seconds passed since January 1, 1970.
tokenstringRandomly generated string with length of 50.
signaturestringString with hexadecimal digits generated by an HMAC algorithm

To verify the webhook originated from Mailgun, you will need to:

  • Concatenate timestamp and token values together with no separator.
  • Encode the resulting string with the HMAC algorithm, using your Webhook Signing Key as a key and SHA256 digest mode.
  • Compare the resulting hexdigest to the signature. If they do not match then the webhook is not from Mailgun!
  • Optionally, you can cache the token value locally and not honor any subsequent request with the same token. This will prevent replay attacks.
  • Optionally, you can check if the timestamp is not too far from the current time.
    • There can be delays in webhook processing that are outside of Mailgun's control so you don't want to be too aggressive with this check.

To visualize, here's a sample NodeJS snippet that checks the Webhook signature:

const crypto = require('crypto')

const verify = ({ signingKey, timestamp, token, signature }) => {
    const encodedToken = crypto
        .createHmac('sha256', signingKey)
        .update(timestamp.concat(token))
        .digest('hex')

    return (encodedToken === signature)
}

TLS Client Authentication

If your receiving server uses valid TLS configuration - Mailgun includes a TLS client certificate with our Webhook requests. This allows customers to use transport-level validation by inspecting the TLS certificate provided in the request to perform additional validation for whether the request originated from Mailgun.

How it works:

  • Mailgun includes our TLS client certificate in webhook requests, which is owned and managed by Mailgun and is issued by DigiCert
  • Your server should be configured to only accept requests from clients with valid TLS certificates issued by a trusted CA (e.g., DigiCert)
  • Once you've confirmed the certificate is valid: then verify that the certificate's Common Name (CN) is webhooks.mgsend.net
Warning!

We do not support validation of server certificates issued by custom CA’s on Mailgun's side before sending, i.e mutual TLS (mTLS)

You can download the current certificate for inspection from our US or EU API.