webhookWebhooks

Webhooks allow you to receive all information about your deliverability and activities within your account (Audit Log) almost in real-time.

Event types

Sending events:

  • Delivery - Email successfully delivered

  • Bounce - Permanent delivery failure

  • Soft bounce - Temporary failure (will retry)

  • Spam complaint - Recipient reported spam

  • Unsubscribe - Recipient unsubscribed

  • Open - Email was opened

  • Click - Link was clicked

  • Suspension - Message suspended

  • Reject - Message rejected

Audit Log events (available for enterprise only):

  • User login events

  • Profile updates

  • Permission changes

  • And more

How to set up webhooks

1

Navigate to SettingsWebhooks and click the Create New Webhook button.

2

Enter a valid Webhook URL. Use a password and username as an extra security layer with basic authorization to prevent others from sending information to that endpoint. You can also use a token as a query parameter or use webhook signaturearrow-up-right.

3

Choose the Payload format (JSON or JSON Lines).

Examples of payload:

Events sent as a JSON object with an events array:

4

Select the webhooks area (Audit Log or Email Sending).

If you choose Audit Log, you will receive events related to all activities within your account that are supported by the Activity Log.

If you choose Email Sending, you'll also need to:

1

Choose the Sending Stream (Transactional or Bulk) for which you want to set up the webhooks.

circle-info

Transactional Stream is used to send user-triggered emails to one recipient at a time, while Bulk Stream is used to send promotional emails to multiple recipients at once.

2

Choose the domain you want to receive events' data for and select one or more event types by ticking the corresponding checkbox.

3

Click the Run Test button to test the webhook setup. The code represents a dummy payload of the webhook structure and how to read it correctly. If your endpoint responds with a 200 code, you'll see a confirmation in the app. All other response codes show an error during a test.

circle-info

One popular way to test webhooks outside your system is Webhook.sitearrow-up-right, but don't use it for production.

4

If the tests are successful, click the Save button. All information will be sent to your webhook endpoint.

circle-info

To edit, pause, or delete an active webhook, go back to the Webhooks tab and select the webhook you want to change.

circle-exclamation

Receive events (JSON format)

Receive webhook events as a JSON object containing an array of events.

Set Payload format: JSON in your webhook settings.

Mailtrap sends a POST request to your webhook URL with events as a JSON object.

Your endpoint should:

  • Accept Content-Type: application/json

  • Return HTTP 200 to acknowledge receipt

  • Process events asynchronously

Payload

events one of[] optional

chevron-rightobject · SendingWebhookEvent optional Email lifecycle webhook eventhashtag

event string · enum required Event type Possible values: delivery open click unsubscribe spam soft bounce bounce suspension reject

message_id string required Unique message ID

sending_stream string · enum required Sending stream used Possible values: transactional bulk

email string required Recipient email address

sending_domain_name string required Sending domain name

category string optional Category assigned when sending

custom_variables object optional Custom variables from the email

  • Other properties string | number | boolean optional

timestamp integer required Unix epoch timestamp

event_id string required Unique event ID (use for idempotency)

reason string optional Reason (for suspension and reject events)

response string optional Server response (for soft bounce and bounce events)

response_code integer optional SMTP response code (for soft bounce and bounce events)

bounce_category string optional Bounce category (for soft bounce and bounce events)

ip string optional User IP address (for open, click, unsubscribe events)

user_agent string optional User agent (for open, click, unsubscribe events)

url string optional Clicked URL (for click events)

chevron-rightobject · ActivityLogWebhookEvent optional Account activity webhook event (Enterprise only)hashtag

event string required Activity log event type Example: activity_log.user.updated

description string required User-friendly event description Example: updated the user profile

actor object required User or system that performed the action

  • id integer optional Actor ID Example: 1

  • type string · enum optional Actor type Possible values: user api_token

  • name string optional Actor name Example: John Doe

resource object optional Affected resource (optional)

  • id string optional Resource ID Example: 1

  • type string · enum optional Resource type Possible values: user api_token billing account sso_config sending_domain project inbox contact_list contact_field contact_segment

  • name string optional Resource name Example: John Doe

changes object optional Changes made (optional) Example: {"name":{"from":"John","to":"John Doe"}}

  • Other properties object optional

timestamp integer required Unix epoch timestamp Example: 1735830138

Responses

200

Return 200 to acknowledge successful receipt

500

Any other status triggers retry (40 retries every 5 min)

Payload

Receive events (JSON Lines format)

Mailtrap sends a POST request to your webhook URL with events in JSON Linesarrow-up-right format.

Each line is a separate JSON object. Parse line by line.

Your endpoint should:

  • Accept Content-Type: application/jsonl

  • Return HTTP 200 to acknowledge receipt

  • Process events asynchronously

Payload

chevron-rightobject · SendingWebhookEvent optional Email lifecycle webhook eventhashtag

event string · enum required Event type Possible values: delivery open click unsubscribe spam soft bounce bounce suspension reject

message_id string required Unique message ID

sending_stream string · enum required Sending stream used Possible values: transactional bulk

email string required Recipient email address

sending_domain_name string required Sending domain name

category string optional Category assigned when sending

custom_variables object optional Custom variables from the email

  • Other properties string | number | boolean optional

timestamp integer required Unix epoch timestamp

event_id string required Unique event ID (use for idempotency)

reason string optional Reason (for suspension and reject events)

response string optional Server response (for soft bounce and bounce events)

response_code integer optional SMTP response code (for soft bounce and bounce events)

bounce_category string optional Bounce category (for soft bounce and bounce events)

ip string optional User IP address (for open, click, unsubscribe events)

user_agent string optional User agent (for open, click, unsubscribe events)

url string optional Clicked URL (for click events)

chevron-rightobject · ActivityLogWebhookEvent optional Account activity webhook event (Enterprise only)hashtag

event string required Activity log event type Example: activity_log.user.updated

description string required User-friendly event description Example: updated the user profile

actor object required User or system that performed the action

  • id integer optional Actor ID Example: 1

  • type string · enum optional Actor type Possible values: user api_token

  • name string optional Actor name Example: John Doe

resource object optional Affected resource (optional)

  • id string optional Resource ID Example: 1

  • type string · enum optional Resource type Possible values: user api_token billing account sso_config sending_domain project inbox contact_list contact_field contact_segment

  • name string optional Resource name Example: John Doe

changes object optional Changes made (optional) Example: {"name":{"from":"John","to":"John Doe"}}

  • Other properties object optional

timestamp integer required Unix epoch timestamp Example: 1735830138

Responses

200

Return 200 to acknowledge successful receipt

500

Any other status triggers retry (40 retries every 5 min)

Payload

Activity log event structure

Activity log events include the following fields:

  • event — The event type

    • Example: activity_log.user.updated

  • description — The event description. Meant to be a user-friendly representation of the event type.

    • Example: updated the user profile

  • actor — Object representing the actor who executed the action or if the action was performed by the system actor.

    • Example: {"id":1,"type":"user","name":"Jack"} or {"name":"Mailtrap"}

  • resource — Optional object representing the resource affected by the action

    • Example: {"id":17,"type":"sandbox","name":"Main"}

  • changes — Optional object representing the changes made to the resource

    • Example: {"name":{"from":"John","to":"John Doe"}}

  • timestamp — The timestamp in Unix epoch format

    • Example: 1735830138

All stats are built on the events, and you get most event information from the Mailtrap UI.

Retry schedule and batches

Retry schedule

If your endpoint is down and doesn't respond with 200 OK, we'll retry multiple times. The scheduling logic is as follows:

  • Retry - 40 retries every 5 minutes. The webhook will be considered failed if we don't receive 200 OK with all retries. If the webhook fails, we'll pause it and notify you by email. You'll need to check its settings and resume it manually.

  • Timeout - 30 seconds. If your endpoint doesn't respond within that time, the webhook event batch will go to the retry schedule.

Batches

Webhooks are delivered in batches, so a single request can contain multiple events. This reduces the number of requests to your endpoint and lowers load on your infrastructure.

Mailtrap can include up to 500 events per delivery. Events are collected and sent every 30 seconds (if there are events to deliver).

The batch format depends on the webhook payload type you choose:

  • JSON: events are sent as a JSON array in a single payload.

  • JSON Lines: events are sent as one JSON object per line (not wrapped in an array).

Webhook Signature Verification

Mailtrap signs all webhook requests to ensure they originate from Mailtrap and haven't been tampered with.

Overview

Mailtrap uses HMAC-SHA256arrow-up-right to sign webhook payloads. Each webhook has a unique signing secret that you can use to verify the authenticity of incoming requests.

How it works

  • Signature Header – Mailtrap includes a `Mailtrap-Signature` header in every webhook request.

  • Signature Algorithm – The signature is computed using HMAC-SHA256.

  • Signature Format – The signature is a hexadecimal-encoded string.

  • Signing Secret – Each webhook has a unique signing secret (32 hex characters).

Getting your signing secret

The signing secret is automatically generated when you create a webhook. You can view and manage your signing secret in the Mailtrap UI:

1

Find the webhook you want to configure in to your webhooks settings

2

The signing secret will be displayed in the webhook details

Then, you can:

  • Copy the secret to use in your verification code.

  • Reset it at any time from the UI if you wish to (i.e., for security reasons).

Important: When you reset the signing secret, the old secret becomes invalid immediately. Make sure to update your verification code with the new secret.

Verifying the signature

To verify a webhook signature, you need to:

  1. Extract the `Mailtrap-Signature` header from the incoming request

  2. Get the raw request body (as bytes/string, not parsed JSON)

  3. Compute HMAC-SHA256 using your signing secret and the raw body

  4. Compare the computed signature with the header value using a constant-time comparison

Important notes:

  • Use the raw request body – Do not parse the JSON first. Use the raw bytes/string exactly as received.

  • Constant-time comparison – Always use a constant-time comparison function to prevent timing attacks.

  • Content-Type – The signature is computed on the raw body regardless of Content-Type (JSON or JSONL)

Code examples

Security best practices

  • Always verify signatures – Never process webhooks without verifying the signature first.

  • Store secrets securely – Keep your signing secrets in environment variables or secure secret management systems.

  • Use constant-time comparison – Always use constant-time comparison functions to prevent timing attacks.

  • Handle missing headers gracefully – If the signature header is missing, reject the request.

  • Rotate secrets when compromised – If you suspect a secret has been compromised, reset it immediately in the Mailtrap UI.

Troubleshooting

Signature verification fails:

  • Check the raw body – Make sure you're using the raw request body, not parsed JSON.

  • Verify encoding – Ensure you're handling UTF-8 encoding correctly.

  • Check secret – Confirm you're using the correct signing secret for the webhook.

  • Header name – The header is case-insensitive, but ensure you're reading it correctly (`Mailtrap-Signature`).

Signature header is missing:

  • This could indicate the request is not from Mailtrap

  • Reject the request with a 400 Bad Request status

Different payload formats:

  • The signature is computed on the raw body regardless of payload format (JSON or JSONL)

  • Both formats use the same verification process

Last updated

Was this helpful?