# Webhook Documentation

![](/assets/email-webhooks.svg)

Webhooks are a feature that allow you to receive event payloads sent directly to your server in response to predefined events such as new emails, inbound SMS messages, or account bounces. Webhooks can be attached to inboxes, phone numbers, or to your account. See the [event type payloads](#event-types) below for schema examples.

![webhooks](/mermaid-gen/webhooks-full.mmd.svg)

## About

<figure data-component="DocsVideoEmbed" class="docs-video-embed">
<iframe src="https://www.youtube-nocookie.com/embed/smkEekUnqu8?modestbranding=1&rel=0&controls=1" title="MailSlurp documentation video" loading="lazy" allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
<figcaption><a href="https://www.youtube.com/watch?v=smkEekUnqu8">Open video on YouTube</a></figcaption>
</figure>

Why use webhooks? Webhooks let you respond to events when they occur. They remove the need to continually poll the MailSlurp API to request the latest emails. This mitigates rate-limiting errors. Webhooks also enable graceful error handling because they are backed by a queue and can be retried over time when your server is down or throwing exceptions.

### Webhook Event types

Webhook events are listed below. Each event type indicates the triggering action for the webhook. For instance `NEW_EMAIL` webhooks are triggered when an inbox they are attached to receives a new email.

<div data-component="DocsWebhookEventList" class="docs-webhook-event-list" aria-label="Webhook event types">
<a class="docs-webhook-event-link" href="/docs/api/#WebhookNewEmailPayload" data-event-name="EMAIL_RECEIVED"><span class="docs-webhook-event-name"><code>EMAIL_RECEIVED</code></span><span class="docs-webhook-event-description">Inbox received an email payload.</span><span class="docs-webhook-event-schema">WebhookNewEmailPayload</span></a>
<a class="docs-webhook-event-link" href="/docs/api/#WebhookNewAITransformResultPayload" data-event-name="NEW_AI_TRANSFORM_RESULT"><span class="docs-webhook-event-name"><code>NEW_AI_TRANSFORM_RESULT</code></span><span class="docs-webhook-event-description">AI transformer produced a new extraction result.</span><span class="docs-webhook-event-schema">WebhookNewAITransformResultPayload</span></a>
<a class="docs-webhook-event-link" href="/docs/api/#WebhookNewEmailPayload" data-event-name="NEW_EMAIL"><span class="docs-webhook-event-name"><code>NEW_EMAIL</code></span><span class="docs-webhook-event-description">New email received by an inbox.</span><span class="docs-webhook-event-schema">WebhookNewEmailPayload</span></a>
<a class="docs-webhook-event-link" href="/docs/api/#WebhookNewContactPayload" data-event-name="NEW_CONTACT"><span class="docs-webhook-event-name"><code>NEW_CONTACT</code></span><span class="docs-webhook-event-description">Contact created from inbound email activity.</span><span class="docs-webhook-event-schema">WebhookNewContactPayload</span></a>
<a class="docs-webhook-event-link" href="/docs/api/#WebhookNewAttachmentPayload" data-event-name="NEW_ATTACHMENT"><span class="docs-webhook-event-name"><code>NEW_ATTACHMENT</code></span><span class="docs-webhook-event-description">Email attachment detected for a received message.</span><span class="docs-webhook-event-schema">WebhookNewAttachmentPayload</span></a>
<a class="docs-webhook-event-link" href="/docs/api/#WebhookEmailOpenedPayload" data-event-name="EMAIL_OPENED"><span class="docs-webhook-event-name"><code>EMAIL_OPENED</code></span><span class="docs-webhook-event-description">Tracked email open event.</span><span class="docs-webhook-event-schema">WebhookEmailOpenedPayload</span></a>
<a class="docs-webhook-event-link" href="/docs/api/#WebhookEmailReadPayload" data-event-name="EMAIL_READ"><span class="docs-webhook-event-name"><code>EMAIL_READ</code></span><span class="docs-webhook-event-description">Email read event.</span><span class="docs-webhook-event-schema">WebhookEmailReadPayload</span></a>
<a class="docs-webhook-event-link" href="/docs/api/#WebhookDeliveryStatusPayload" data-event-name="DELIVERY_STATUS"><span class="docs-webhook-event-name"><code>DELIVERY_STATUS</code></span><span class="docs-webhook-event-description">Delivery status update for a sent email.</span><span class="docs-webhook-event-schema">WebhookDeliveryStatusPayload</span></a>
<a class="docs-webhook-event-link" href="/docs/api/#WebhookBouncePayload" data-event-name="BOUNCE"><span class="docs-webhook-event-name"><code>BOUNCE</code></span><span class="docs-webhook-event-description">Account-level email bounce event.</span><span class="docs-webhook-event-schema">WebhookBouncePayload</span></a>
<a class="docs-webhook-event-link" href="/docs/api/#WebhookBounceRecipientPayload" data-event-name="BOUNCE_RECIPIENT"><span class="docs-webhook-event-name"><code>BOUNCE_RECIPIENT</code></span><span class="docs-webhook-event-description">Recipient bounce event for an email address.</span><span class="docs-webhook-event-schema">WebhookBounceRecipientPayload</span></a>
<a class="docs-webhook-event-link" href="/docs/api/#WebhookNewSmsPayload" data-event-name="NEW_SMS"><span class="docs-webhook-event-name"><code>NEW_SMS</code></span><span class="docs-webhook-event-description">Phone number received an SMS message.</span><span class="docs-webhook-event-schema">WebhookNewSmsPayload</span></a>
<a class="docs-webhook-event-link" href="/docs/api/#AbstractWebhookPayload" data-event-name="NEW_GUEST_USER"><span class="docs-webhook-event-name"><code>NEW_GUEST_USER</code></span><span class="docs-webhook-event-description">Guest user event payload.</span><span class="docs-webhook-event-schema">AbstractWebhookPayload</span></a>
</div>

See the [event documentation](/docs/webhooks/#event-types) for details on each type.

### Delivery and idempotency

MailSlurp webhooks are guaranteed to be delivered **at least once** - this means the same payload could be sent to your endpoint twice. For this reason it is important to use the `messageId` unique to all payloads to avoid processing a message twice. Save this idempotency key on your server and perform a lookup when new messages arrive and discard those you have already processed.

### Message payload

When a webhook is triggered for its event type a corresponding JSON payload is posted to the webhook's URL via HTTP. See the [event type documentation](/docs/webhooks/#event-types) below for schemas. Each [MailSlurp library](/docs/js/) contains webhook payload types that extend AbstractWebhookPayload. Use the `eventName` property or the `x-event` header to cast the event to an appropriate concrete type.

```typescript
function handleWebhookPayload(body: AbstractWebhookPayload) {
  // use the event name to cast the event
  if (body.eventName === AbstractWebhookPayloadEventNameEnum.NEW_EMAIL) {
    const event = body as unknown as WebhookNewEmailPayload;
    // now access event properties and process
    log.info(event.emailId);
  } else {
    throw new Error('Unexpect webhook event');
  }
}
```

Or for simpler usage parse the request body into your expected payload:

```typescript
const newEmail: WebhookNewEmailPayload = JSON.parse(requestBody);
log.info(
  `New email from ${newEmail.from} with subject ${newEmail.subject}`
);
```

### IP address range whitelist

MailSlurp sends webhooks from a static IP list if you use the `useStaticIpRange` flag when creating the webhook.

| Public IP4 Address |
| ------------------ |

| Use the dashboard or contact support for the current static IP range. |

To use static IP webhooks in code do the following:

```typescript
// create a webhook with static ip
const webhook = await webhookController.createWebhook({
  inboxId: inbox.id,
  createWebhookOptions: {
    eventName: CreateWebhookOptionsEventNameEnum.NEW_CONTACT,
    // send test webhook to service that returns caller ip address
    url: 'https://f.mailslurp.link/f/getip',
    // must set static ip flag to enable
    useStaticIpRange: true
  }
});
// send test webhook
const result = await webhookController.sendTestData({
  webhookId: webhook.id
});
// check ip address in result
expect(publiclyKnownStaticIpRange).toContain(result.response.message);
```

White list these IP addresses in your network firewall if you are having trouble receiving webhooks. Contact [support](https://www.mailslurp.com/support/) for help.

### Custom payload and redirect

You can customize the shape of the event payload for use with other services such as Slack or Teams by providing a `requestBodyTemplate` property containing templated JSON.

```typescript
await mailslurp.webhookController.createWebhook({
  inboxId: inbox.id,
  createWebhookOptions: {
    eventName: CreateWebhookOptionsEventNameEnum.NEW_EMAIL,
    url: slackIncomingWebhookUrl,
    // custom request body for slack uses {{subject}} to insert
    // the subject from the standard NEW_EMAIL payload
    requestBodyTemplate: `{"text":"New message: {{subject}}"}`,
  },
});
```

Use [mustache](https://mustache.github.io/) style templating to insert properties from the standard payload for the event into your custom payload.

### Sent headers

Each webhook is sent via HTTP with the following headers:

| Header        | Example           | Description                                                                                  |
| ------------- | ----------------- | -------------------------------------------------------------------------------------------- |
| x-from        | api.mailslurp.com | Header identifying the server sending the webhook. Is always equal to api.mailslurp.com      |
| x-event       | NEW_EMAIL         | Webhook event type for the payload. What triggered the event.                                |
| x-signature   | sig-29s033if2     | Signature for the event. Use this with webhook signature verify endpoint to verify payload.  |
| x-message-id  | 38547638          | Unique ID for the webhook payload. Use this ID to avoid processing a webhook multiple times. |
| Authorization | Basic xdsf924     | Basic authentication. Only set if your webhook was created with a username and password.     |

You can add custom headers when you create a webhook and these header name value pairs will be sent with every request. Use these static headers in your application if required. See the static header section for more information.

## Create and manage webhooks

Webhooks can be created in the MailSlurp dashboard or using the [API WebhookController](/docs/api/). Webhooks can be attached to an inbox or phone number or created without one depending on the event type.

![Create email webhook](/assets/app/create-webhook.png)

Here is an example creating an inbox related webhook using the [MailSlurp Javascript client](/docs/js/).

```typescript
const inbox = await mailslurp.createInbox();
const webhook = await mailslurp.webhookController.createWebhook({
  inboxId: inbox.id!,
  createWebhookOptions: {
    eventName: CreateWebhookOptionsEventNameEnum.NEW_EMAIL,
    url: testEndpoint.url!!,
  },
});
```

### Account scoped webhooks

Or for account based events such as BOUNCE pass null for the inbox ID:

```typescript
const webhook = await mailslurp.webhookController.createAccountWebhook({
  createWebhookOptions: {
    eventName: CreateWebhookOptionsEventNameEnum.BOUNCE,
    url: testEndpoint.url!!,
  },
});
```

Account based webhooks are useful for processing events for every inbox or your whole account. For example: you can use a single account webhook with the `NEW_EMAIL` type to receive all inbound emails across each of your inboxes with one webhook.

### Phone based webhooks

SMS related events support phone number scoping like so:

```typescript
await mailslurp.webhookController.createWebhookForPhoneNumber({
  phoneNumberId: phone.id,
  createWebhookOptions: {
    eventName: CreateWebhookOptionsEventNameEnum.NEW_SMS,
    url: testEndpoint.url!!
  }
});
```

### Set static headers

MailSlurp can send static headers with each HTTP header. Use the `includeHeaders` option when creating the webhook and POST requests to your server will include the provided name value key pairs.

```typescript
// create webhook
const createWebhookOptions: CreateWebhookOptions = {
  name: "my-webhook",
  url: "https://your.server",
  includeHeaders: {
    headers: [{ name: "x-test-header", value: "123" }],
  },
};
const webhook = await webhookController.createWebhook({
  inboxId: inbox.id!!,
  createWebhookOptions: createWebhookOptions,
});
```

### Authentication

If you with to secure your endpoint you can add basic authentication headers to the request by specifying a username and password upon webhook creation. These will be passed in an `Authorization` header with the value `Basic <credentials>` where the credentials are a [base64 encoded string](https://en.wikipedia.org/wiki/Basic_access_authentication) containing the username and password separated by a colon.

## Setup your server

To receive webhook payloads you must expose a public HTTP/S endpoint on your server that responses with a 200-299 status code. If you respond with a 3xx or error code the payload will be placed on a queue and retried with a backoff period.

### Example handler

You can use any framework or server you wish to handle MailSlurp webhooks. Here is an example using NodeJS to illustrate:

```typescript
import { WebhookNewSmsPayload } from 'mailslurp-client';

import bodyParser from 'body-parser';
import express from 'express';

// create a server
const app = express();
app.use(bodyParser());

/**
 * Define an endpoint on your server for the NEW_SMS webhook event
 */
app.post('/inbound/new-sms', (request, response) => {
  // access the data on request body
  // and cast to the expected event type take action
  const sms = request.body as WebhookNewSmsPayload;
  // access the entity
  log.info(`New SMS from ${sms.fromNumber}`);
  // return a 2xx status code so MailSlurp knows you received it
  response.sendStatus(200);
});
```

### Verify webhook signature

MailSlurp sends an `x-signature` header that can be used with the `x-message-id` header to verify a webhook payload.

```javascript
const signature = request.header("x-signature");
const messageId = request.header("x-message-id");
const { isValid } = await mailslurp.webhookController.verifyWebhookSignature({
  verifyWebhookSignatureOptions: { signature, messageId },
});
expect(isValid).toBeTruthy();
```

## Results and redrive

You can view webhook delivery results in the dashboard webhooks page. Webhooks are backed by a queue system that will retry payload posting when error response codes are returned.

![webhook history](/assets/app/webhook-history.png)

## Event types

Each webhook you create responds to a single event type. Webhooks are triggered when the webhook's inbox or your account triggers the corresponding event. MailSlurp will send a JSON payload to the URL specified for your webhook via HTTP/S POST. Each event has a different payload as documented below.

<div data-component="DocsWebhookPayloadIndex" class="docs-webhook-payload-index">
<p>Open each event payload schema in the API reference.</p>
<ul class="docs-webhook-payload-links">
<li data-event-name="EMAIL_RECEIVED"><a href="/docs/api/#WebhookNewEmailPayload"><code>EMAIL_RECEIVED</code> payload schema</a></li>
<li data-event-name="NEW_AI_TRANSFORM_RESULT"><a href="/docs/api/#WebhookNewAITransformResultPayload"><code>NEW_AI_TRANSFORM_RESULT</code> payload schema</a></li>
<li data-event-name="NEW_EMAIL"><a href="/docs/api/#WebhookNewEmailPayload"><code>NEW_EMAIL</code> payload schema</a></li>
<li data-event-name="NEW_CONTACT"><a href="/docs/api/#WebhookNewContactPayload"><code>NEW_CONTACT</code> payload schema</a></li>
<li data-event-name="NEW_ATTACHMENT"><a href="/docs/api/#WebhookNewAttachmentPayload"><code>NEW_ATTACHMENT</code> payload schema</a></li>
<li data-event-name="EMAIL_OPENED"><a href="/docs/api/#WebhookEmailOpenedPayload"><code>EMAIL_OPENED</code> payload schema</a></li>
<li data-event-name="EMAIL_READ"><a href="/docs/api/#WebhookEmailReadPayload"><code>EMAIL_READ</code> payload schema</a></li>
<li data-event-name="DELIVERY_STATUS"><a href="/docs/api/#WebhookDeliveryStatusPayload"><code>DELIVERY_STATUS</code> payload schema</a></li>
<li data-event-name="BOUNCE"><a href="/docs/api/#WebhookBouncePayload"><code>BOUNCE</code> payload schema</a></li>
<li data-event-name="BOUNCE_RECIPIENT"><a href="/docs/api/#WebhookBounceRecipientPayload"><code>BOUNCE_RECIPIENT</code> payload schema</a></li>
<li data-event-name="NEW_SMS"><a href="/docs/api/#WebhookNewSmsPayload"><code>NEW_SMS</code> payload schema</a></li>
<li data-event-name="NEW_GUEST_USER"><a href="/docs/api/#AbstractWebhookPayload"><code>NEW_GUEST_USER</code> payload schema</a></li>
</ul>
</div>

