# Mailparser Webhooks

Mailparser extracts structured data from emails and attachments. An
**Advanced Webhook** sends the parsed data to a URL you choose as soon as an
email has been parsed. You control the HTTP verb, content type, body template
and extra headers.

## When to Use This Skill

* How do I receive Mailparser webhooks?
* How do I authenticate / verify a Mailparser webhook?
* Why is my Mailparser webhook header check failing?
* How do I handle parsed email data from Mailparser?
* How do I handle "one request per row" table webhooks?
* Does Mailparser sign webhooks with an HMAC?

## No Signature: Additional Headers Only

Mailparser's documentation describes **no signature, HMAC or timestamp
header** (ignore third-party claims of one). Instead, an Advanced Webhook has
an **Additional Headers** field: one `Name: value` header per line, sent
unchanged on every request. The docs' example is an `Authorization: Basic ...`
header.

```
X-Webhook-Secret: 3f9c1e...a random value from `openssl rand -hex 32`

```

Pick one header (a secret header such as `X-Webhook-Secret`, or
`Authorization: Basic ...`), and compare the **whole** value in constant time
on every request. Without it, anyone who knows the URL can post fake data.

## Verification (core)

```javascript
const crypto = require('crypto');

const HEADER = (process.env.MAILPARSER_WEBHOOK_HEADER || 'x-webhook-secret').toLowerCase();
const EXPECTED = process.env.MAILPARSER_WEBHOOK_SECRET; // exact value set in Mailparser

function verifyMailparserHeader(received, expected) {
  if (!received || !expected) return false;                // fail closed
  const a = Buffer.from(String(received), 'utf8');         // the WHOLE header value
  const b = Buffer.from(String(expected), 'utf8');
  return a.length === b.length && crypto.timingSafeEqual(a, b); // length guard first
}

// In the handler: verifyMailparserHeader(req.headers[HEADER], EXPECTED)

```

> **For complete handlers with tests**, see [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/mailparser-webhooks/examples/express/), [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/mailparser-webhooks/examples/nextjs/), [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/mailparser-webhooks/examples/fastapi/).

Mailparser has no SDK, so every example compares directly
(`crypto.timingSafeEqual` in Node, `hmac.compare_digest` in Python).
Authenticate before you parse the body.

## Payload and Events

Mailparser has **no event types**: an Advanced Webhook fires when an email has
been parsed. The body is whatever you put in the **HTTP Body Payload
Template** (Handlebars, e.g. `{"invoice_no": "{{InvoiceNumber}}"}`), sent as
JSON or form data depending on the **Content-Type** you choose. So the field
names are your own parsing-rule names, not a fixed schema.

| Setting | Effect |
| --- | --- |
| What data to send: default | One request per email, with all parsed data |
| What data to send: "One request per row" | One request per parsed table row |
| HTTP Verb | `POST` by default; `GET`, `PUT`, `DELETE` also available (use POST) |
| Webhook Delay | Optional delay between calls |

There is no event ID, so add a unique field to your template (such as a
document or message identifier you parse) or hash the raw body for
idempotency. See [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/mailparser-webhooks/references/overview.md).

## Environment Variables

```bash
# Header name you added under Additional Headers (case-insensitive). Default: X-Webhook-Secret
MAILPARSER_WEBHOOK_HEADER=X-Webhook-Secret
# The exact header value you added in Mailparser
MAILPARSER_WEBHOOK_SECRET=your_random_secret

```

With no `MAILPARSER_WEBHOOK_SECRET`, the examples reject every request with a
500 rather than accept unauthenticated webhooks.

## Local Development

```bash
npx hookdeck-cli listen 3000 mailparser --path /webhooks/mailparser

```

No account required — the CLI creates a guest account on first run and gives
you a public HTTPS URL plus a web UI for inspecting requests (including your
custom header). Use port `8000` for the FastAPI example.

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/mailparser-webhooks/references/overview.md) — Payload model, per-row requests, idempotency
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/mailparser-webhooks/references/setup.md) — Creating an Advanced Webhook and its headers
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/mailparser-webhooks/references/verification.md) — Header authentication in detail, gotchas, debugging