MailSlurp logo

guides

Email to webhook guide for inbound automation

Route inbound email to your server in real time with HTTP webhooks. Learn how to build reliable email webhook and email-to-webhook automation for support, finance, and operations workflows.

Email to webhook guide for inbound automation article preview

An incoming email can create a support ticket, start an invoice review, or update an order without anyone copying it out of a mailbox. Email webhooks make that possible by sending message events to your application's HTTP endpoint.

MailSlurp receives the email and posts a JSON payload to your server. Your handler checks the event, saves a job, and uses the email ID to fetch the body or attachments. This guide follows that path, including the point where a retry can accidentally create a second ticket.

Quick answer: what is email to webhook?

Email to webhook means converting inbound email events into HTTP POST callbacks so your systems can process messages in real time.

Instead of polling an inbox every few minutes, your application receives structured events immediately and decides what to do next: create a ticket, extract an attachment, update an order, or trigger a review workflow.

When to use email to webhook

Use email to webhook when an inbound message should start an application workflow, not sit in a shared mailbox.

Customer job How MailSlurp helps
Receive a customer reply and update a product record Assign a dedicated inbox to the workflow and post each new email event to your handler.
Convert vendor invoices or receipts into back-office tasks Trigger a webhook, fetch the message and attachments, then pass the data into parsing or review.
Route support messages into a ticket queue Use inboxes, aliases, and rules so each queue receives only the messages it owns.
Replace no-reply senders with monitored replies Send from a role address, receive replies in MailSlurp, then trigger the right support, billing, or lifecycle workflow.
Test signup, OTP, or password reset messages in CI Create test inboxes and webhooks so release checks can assert that real email events arrived.
Connect inbound email to AI extraction Send the webhook event into a worker that calls MailSlurp parsing and structured extraction APIs.

How email webhooks work

Email webhook API

  1. Create or choose an inbox
  2. Register a webhook URL
  3. Select event type
  4. Receive JSON payloads on matching events
  5. Durably save the pending work and return a 2xx acknowledgement

Useful payload fields to persist first:

Field Why it matters
eventName Confirms the handler is processing the expected event type, such as NEW_EMAIL.
webhookId Identifies which MailSlurp webhook generated the event.
inboxId Keeps routing tied to the mailbox that owns the workflow.
messageId Identifies the webhook notification. Use it to deduplicate repeated delivery of that event.
emailId Identifies the received email. Use it to fetch the message with the email API.
createdAt Helps operators debug delayed handlers, retries, and downstream queue latency.

In practice, the safest architecture is:

  1. Receive the webhook.
  2. Authenticate the request and validate its event, webhook, and inbox IDs.
  3. Durably save the event and its pending work together, then acknowledge it.
  4. Have a worker fetch the email and process attachments or routing separately.

That keeps your endpoint fast enough for retries while still giving downstream systems the full message context they need.

Common webhook event types

  • NEW_EMAIL or EMAIL_RECEIVED
  • NEW_CONTACT
  • NEW_ATTACHMENT

Each event has a typed payload documented in MailSlurp webhook docs.

For most inbound automation projects, NEW_EMAIL is the main entry point. Use more specific event subscriptions only when a downstream system really needs them, otherwise you create unnecessary branching and operational noise.

Create a webhook with API

import { CreateWebhookOptionsEventNameEnum } from "mailslurp-client";

const webhook = await mailslurp.webhookController.createWebhook({
  inboxId,
  createWebhookOptions: {
    url: "https://api.example.com/webhooks/mailslurp-email",
    eventName: CreateWebhookOptionsEventNameEnum.NEW_EMAIL,
  },
});

You can also create webhooks in the dashboard:

email webhook

Receive the email webhook in Node

The key ordering rule is simple: save the work before returning success. If the server returns 200 and then fails to enqueue the job, MailSlurp has an acknowledgement while your application has nothing to process.

This Express-compatible handler uses the MailSlurp signature verification API. Pass a configured MailSlurp client, the expected inbox and webhook IDs, and your database's saveJobOnce function. Mount it after your JSON body parser on the URL you registered.

export function createEmailWebhookHandler({
  mailslurp, inboxId, webhookId, saveJobOnce,
}) {
  return async (request, response) => {
    const event = request.body;
    const messageId = request.get("x-message-id");
    const signature = request.get("x-signature");

    if (!signature || !messageId) {
      return response.status(401).json({ accepted: false });
    }
    if (!event || event.messageId !== messageId ||
        event.eventName !== "NEW_EMAIL" ||
        event.inboxId !== inboxId || event.webhookId !== webhookId ||
        typeof event.emailId !== "string" || !event.emailId) {
      return response.status(400).json({ accepted: false });
    }

    try {
      const { isValid } = await mailslurp.webhookController.verifyWebhookSignature({
        verifyWebhookSignatureOptions: { messageId, signature },
      });
      if (!isValid) {
        return response.status(401).json({ accepted: false });
      }

      await saveJobOnce({
        messageId,
        emailId: event.emailId,
        inboxId: event.inboxId,
        webhookId: event.webhookId,
      });
      return response.status(200).json({ accepted: true });
    } catch {
      return response.status(503).json({ accepted: false });
    }
  };
}

saveJobOnce is your storage adapter, not a MailSlurp SDK method. It must resolve only after a durable pending job exists, including when a duplicate arrives. One PostgreSQL implementation is a job table with a unique message_id and an awaited parameterized insert:

CREATE TABLE inbound_email_jobs (
  message_id text PRIMARY KEY,
  email_id uuid NOT NULL,
  inbox_id uuid NOT NULL,
  webhook_id uuid NOT NULL,
  status text NOT NULL DEFAULT 'pending'
);

INSERT INTO inbound_email_jobs (message_id, email_id, inbox_id, webhook_id)
VALUES ($1, $2, $3, $4)
ON CONFLICT (message_id) DO NOTHING;

Bind the four values from the job in that order. The stored row is the work queue; a separate worker claims pending rows and records completion. If you use a separate message broker, an outbox transaction can keep the event record and pending publish together. An in-memory set or an unawaited queue call does not survive a process failure.

The signature call verifies the message ID and signature pair. Keep HTTPS, validate the expected inbox and webhook, and fetch the full message from the authenticated MailSlurp API before acting on its contents. Confirm that the fetched email belongs to the expected inbox. The email's sender and text are still external input: a valid webhook is not permission to execute instructions found inside an email.

Example email webhook payload

For the default NEW_EMAIL payload, messageId and emailId have different jobs. This illustrative excerpt shows the routing fields; the full payload also includes recipient and attachment metadata.

{
  "eventName": "NEW_EMAIL",
  "webhookId": "webhook-id",
  "inboxId": "inbox-id",
  "emailId": "email-id",
  "messageId": "message-id",
  "createdAt": "2026-07-24T00:00:00.000Z"
}

For a reliable email-to-webhook API flow:

  1. Accept the event at a public HTTPS endpoint.
  2. Validate that the event type and inbox match the workflow.
  3. Store webhookId, inboxId, emailId, and messageId.
  4. Return 200 after the event's pending work is stored durably.
  5. Fetch the full email from MailSlurp in a worker.
  6. Route the result to Slack, Zapier, a ticketing system, a parser, or an internal API.

Extract email addresses from the webhook payload

The default NEW_EMAIL payload already separates addresses into from, to, cc, and bcc. from is a string; the recipient fields are arrays. Read those fields instead of searching the entire JSON payload with an email-address regex. A regex over everything can accidentally collect addresses quoted in a message or another unrelated value.

The recipient fields describe the received message. Use inboxId to decide which MailSlurp workflow owns it. If you need Reply-To, names, the body, or full headers, fetch the email using emailId; do not substitute the webhook's messageId. A custom requestBodyTemplate or AI transform can change the payload shape, so update the receiver contract when you customize it.

Reliability requirements

Return a fast 2xx response

MailSlurp treats 200-299 responses as acknowledgement. Return one promptly after authentication, validation, and durable acceptance. A 202 also acknowledges delivery; it must not mean "nothing was queued." Redirects and error responses are unsuccessful deliveries. See webhook setup and responses.

Handle retries safely

Retries can deliver the same notification more than once. Deduplicate with messageId, using a database uniqueness constraint so two concurrent requests cannot both create work. Keep completed IDs for your replay window. Separately make the worker's downstream action idempotent: if a ticket was created just before the worker crashed, a retry should find that ticket rather than create another one.

Monitor failures and latency

Track webhook history to detect slow handlers, retries, and downstream dependency failures.

email testing

Common failure modes in production

Parsing too much inside the webhook request

If your handler downloads attachments, runs classification, and talks to multiple internal systems before returning, retries can overlap slow work. Authenticate and durably queue first, acknowledge, then process asynchronously.

Missing inbox-level routing rules

When multiple workflows share one intake path without clear inbox or ruleset boundaries, downstream systems end up inferring too much from sender or subject. Use dedicated inboxes, rulesets, or aliases where possible.

No replay or event history

When a handler fails, operators need a way to inspect what was delivered and retry the workflow safely. Keep event history and make it easy to re-run test messages after a fix.

Test webhook email locally

Use tools like ngrok to expose localhost endpoints during development. Validate request schema and signature logic before production deployment.

You should also test with real message shapes, not only toy payloads:

  • HTML-heavy marketing replies
  • invoice or receipt attachments
  • forwarded support threads
  • automated sender notifications

This is where Testing webhooks and Email Sandbox API help before rollout.

Webhook to send email workflows

A webhook can also start an outbound reply or notification. For example, a supplier's incoming message might create a review task and email the person responsible for it.

With MailSlurp, keep the workflow explicit:

  1. Receive the inbound email webhook.
  2. Validate the sender, inbox, subject, and message ID.
  3. Fetch the email body or attachments if your workflow needs them.
  4. Decide whether the system should send an email, create a ticket, request review, or update a record.
  5. Send follow-up email through your application or MailSlurp email APIs only after the event is deduped and authorized.

This pattern works well for order confirmations, supplier replies, lead-routing acknowledgements, support intake, and review requests. It also avoids sending duplicate responses when a webhook is retried.

Email webhook routing patterns

Pattern Best fit MailSlurp route
One inbox per workflow Finance inboxes, supplier mailboxes, support queues Inbound email routing
Alias or ruleset driven routing Multi-tenant apps, shared intake addresses, regional queues Email automation routing
Webhook plus parser worker Invoices, receipts, claims, forms, attachments AI email parsing
Webhook plus test inboxes CI checks, OTP tests, signup and password reset tests Email Sandbox API

Email to webhook destination examples

Start with one destination and one event type. After the first path is stable, add secondary notifications or parser steps.

Destination What to send first Good first workflow
Internal API emailId, sender, subject, inbox ID, and received timestamp Create or update a customer, order, claim, lead, or support record after a matching inbox receives a reply.
Slack or Teams Sender, subject, workflow name, and a link to the message Notify an operations channel when a supplier, customer, or billing inbox receives a new message.
Zapier or workflow tool Message metadata plus a stable MailSlurp message reference Start a no-code workflow while keeping the original email available for review and replay.
Ticketing system Sender, subject, body summary, attachments, and mailbox owner Convert inbound support email into a ticket with the right queue and priority.
Parser or extraction API Message ID, attachment IDs, sender, and expected output schema Extract invoice, receipt, claim, or lead fields before writing to the destination system.

Use Email webhooks when the main requirement is reliable event delivery, Inbound email routing when multiple teams or queues own the workflow, and AI email parsing when attachments or structured fields drive the next action.

Production checklist for email webhook launches

Before you connect an email webhook to a production workflow, confirm:

  1. The webhook URL uses HTTPS and belongs to the service that owns the workflow.
  2. The handler checks event type, inbox ID, and destination before doing work.
  3. A unique messageId admits one pending job, and the worker protects its own downstream actions against duplicates.
  4. The pending job is durable before the 2xx; slow parsing, attachment downloads, and business updates happen in the worker.
  5. Operators can inspect recent webhook history and rerun failed work safely.
  6. Test inboxes can replay representative messages before a parser, ticketing, Slack, Zapier, or internal API change ships.
  7. Product and support teams know which inboxes, aliases, or rulesets feed each destination.

This checklist keeps email-to-webhook automation dependable as volume grows from one monitored inbox to support, finance, operations, and customer-reply workflows.

FAQ

What is the difference between an email webhook and an inbound email API?

An inbound email API usually gives you ways to create inboxes and read messages. An email webhook is the push-delivery layer that sends message events to your application automatically when they happen.

When should I use email to webhook instead of polling?

Use email-to-webhook when message latency matters, inbox volume is growing, or operators should not have to wait for a polling loop before a workflow starts.

Can I use email webhooks for attachments?

Yes. A common pattern is to receive the event, store the message metadata, then fetch and process attachments asynchronously so your handler stays retry-safe.

What status should an email webhook endpoint return?

Return a 2xx response after your endpoint has authenticated the request and durably accepted its work, or confirmed that the same job already exists. Return an error when validation or storage fails and investigate rejected events in the delivery history. HTTP success confirms receipt by your handler; the worker still needs to finish its task.

Can a webhook send email after receiving a message?

Yes. The webhook should trigger your application logic first. After you validate and dedupe the inbound event, your worker can send a response, create an internal notification, or call a downstream API.

Are email webhooks enough for complex routing on their own?

Combine webhooks with MailSlurp inbox boundaries, routing rules, and parsing when the workflow needs them. For example, separate finance and support inboxes can trigger different workers while sharing the same receiver.

Start with one inbox and one receiver. Create a MailSlurp inbox for inbound automation, then follow the webhook testing guide to prove that one incoming email produces one completed application task.