Email to JSON

Convert inbound email to structured JSON

MailWebhook receives email from Gmail, Microsoft 365, IMAP, or hosted mailboxes, normalizes the message, extracts useful fields, and sends your application JSON in the shape your route defines.

Built for email-to-JSON webhooks, parser workflows, inbound email automation, and applications that need stable payloads instead of raw MIME.

Raw email
From: Vendor Billing <billing@vendor.example>
To: ap@company.com
Subject: Invoice 1042

Invoice ID: INV-1042
Total: $481.92
Due Date: 2026-07-15

Please review the attached PDF invoice.
Route JSON output
{
  "kind": "invoice",
  "invoice_id": "INV-1042",
  "total": "$481.92",
  "due_date": "2026-07-15",
  "vendor": {
    "email": "billing@vendor.example",
    "domain": "vendor.example"
  },
  "attachments": [
    {
      "filename": "invoice-1042.pdf",
      "content_type": "application/pdf",
      "size": 93259
    }
  ]
}

Use MailWebhook to convert email to JSON, replace brittle email parser JSON scripts, and deliver every matching message as an email-to-JSON webhook your application can process.

What is email to JSON?

Email to JSON is a way to turn inbound email messages into structured data that software can process. Instead of handing your application a raw MIME message, an email-to-JSON workflow normalizes senders, recipients, headers, body text, HTML, attachments, timestamps, and selected extracted fields into a predictable JSON payload.

MailWebhook does this inside a route pipeline. A route matches an incoming email, transforms the parsed message, maps it to either the documented generic JSON shape or a custom JSON shape, and delivers that JSON to your webhook endpoint.

See the generic JSON schema

From messy mailbox messages to useful JSON

A route turns each matching email into the JSON your application expects, without a separate parsing service.

  1. Step 1

    Connect a source mailbox

    Use Gmail, Microsoft 365/Outlook, IMAP, or a MailWebhook-hosted mailbox as the source.

  2. Step 2

    Match the message to a route

    Route rules decide which messages should be transformed and delivered.

  3. Step 3

    Normalize the email

    Parsed fields become stable message, body, attachment, header, and context objects.

  4. Step 4

    Extract and map

    Use the generic JSON mapper or configure map.custom_json to emit the payload your receiver expects.

  5. Step 5

    Deliver the JSON

    The route output is serialized as JSON and posted to your endpoint.

Start with a stable schema or shape the payload yourself

map.generic_json

Generic JSON

Use map.generic_json when your receiver wants a documented, deterministic payload. The mailwebhook.generic@1 shape includes schema, event, message, body, meta, and optional envelope objects.

map.custom_json

Custom JSON

Use map.custom_json when your receiver expects a specific contract. The mapper config can read message fields, route context, metadata, computed vars, and extraction-helper output, then emit the JSON object or value your downstream system needs.

NeedUse
Stable MailWebhook-owned event shapemap.generic_json
Receiver-specific payload for CRM, ERP, ticketing, AI, or internal APIsmap.custom_json
Fast implementation with known top-level fieldsGeneric JSON
Fewer transformations after receiptCustom JSON
Strict documented event schemaGeneric JSON
Route-specific extraction fieldsCustom JSON

A documented JSON shape for every matching email

The default mapper emits mailwebhook.generic@1. It keeps the payload predictable: event identifiers in event, email fields in message, body and attachments in body, and source metadata in meta.

Attachments are metadata only. No file URLs or bytes are embedded in the generic JSON body.

Validate the generic shape
mailwebhook.generic@1
{
  "schema": { "name": "mailwebhook.generic", "version": "1" },
  "event": {
    "id": "6ff49aa1-7050-4ad1-95d9-2711f2ca7e88",
    "project_id": "dca29061-c4a7-4687-a8dd-24d2f26548c7",
    "route_id": "2f3713bf-88cc-46c6-aaa3-ea9d6e9d20f3",
    "created_at": "2026-06-27T10:14:32Z"
  },
  "message": {
    "message_id": "<invoice-1042@example.com>",
    "message_id_type": "original",
    "subject": "Invoice 1042",
    "date": "2026-06-27T10:13:59Z",
    "from": [{ "email": "billing@vendor.example", "name": "Vendor Billing" }],
    "to": [{ "email": "ap@company.com" }],
    "headers": {
      "message-id": "<invoice-1042@example.com>",
      "content-type": "multipart/mixed"
    }
  },
  "body": {
    "text": "Please review invoice 1042.",
    "attachments": [
      {
        "id": "9f5a1ded-538d-4f5f-a7a9-d3eacf9e58a0",
        "filename": "invoice-1042.pdf",
        "content_type": "application/pdf",
        "size": 93259,
        "is_inline": false,
        "sha256": "059a0f5260487bbe663994de1fd641401fec76ac9f6bddfe5b53ae60d4bb2d86"
      }
    ]
  },
  "meta": {
    "source": "gmail",
    "raw_size_bytes": 26546,
    "received_at": "2026-06-27T10:14:32Z"
  }
}

Map email fields into the JSON your app already expects

Custom JSON routes let you move transformation before delivery. Instead of receiving a large generic payload and writing another adapter, define the route output from message fields, computed vars, route context, and extraction-helper results.

{
  "steps": [
    {
      "name": "map.custom_json",
      "args": {
        "version": "v1",
        "vars": [
          {
            "name": "sender",
            "expr": { "string.lower": { "var": "message.from[0].email" } }
          },
          {
            "name": "vendor_domain",
            "expr": {
              "regex.replace": {
                "value": { "var": "vars.sender" },
                "pattern": "^.*@([^>\\s]+)$",
                "with": "\\1"
              }
            }
          },
          {
            "name": "is_invoice",
            "expr": {
              "regex.match": {
                "value": { "var": "message.subject" },
                "pattern": "(?i)invoice|receipt|payment"
              }
            }
          }
        ],
        "output": {
          "kind": { "if": [{ "var": "vars.is_invoice" }, "invoice", "message"] },
          "vendor": {
            "email": { "var": "vars.sender" },
            "domain": { "var": "vars.vendor_domain" }
          },
          "subject": { "var": "message.subject" },
          "first_attachment": {
            "filename": { "var": "message.attachments[0].filename" },
            "content_type": { "var": "message.attachments[0].content_type" },
            "size": { "var": "message.attachments[0].size" },
            "sha256": { "var": "message.attachments[0].sha256" }
          }
        }
      }
    }
  ]
}

The mapper config is validated when the route is saved and again before execution. Missing paths evaluate to null, so not every sender will populate every field.

Copy custom JSON recipes

Built-in helpers for the hard parts of email extraction

These helpers handle the fields that usually break parser scripts, so routes can address them with a stable JSON path.

Reply content

Extract only the new reply body from quoted content, forwarded content, and signatures.

vars.reply_segments.text.reply_content
call.extract.reply_segments

Links

Extract URLs from HTML attributes, link text, Markdown links, and plain text.

vars.links[0].url
call.extract.urls

Key/value fields

Turn labels such as Order ID: AZ-123 into normalized lookup fields.

vars.kv.values.order_id
call.extract.key_value_pairs

Tables

Extract text tables, Markdown pipe tables, ASCII tables, native HTML tables, and HTML grids.

vars.tables.tables[0].lookup.by_row.widget.qty
call.extract.tables

Lists

Convert bullet and numbered lists into structured arrays.

vars.lists[0].bullets[0].text
call.extract.bullet_list

DOM fields

Pull repeated records or scalar values from stable HTML layouts using CSS or XPath selectors.

vars.opportunities.items
call.extract.dom
View the mapper DSL

Turn email labels into JSON fields

Key/value extraction normalizes labels so fields can be addressed predictably. For example, Order ID becomes order_id, Customer Email becomes customer_email, and Ticket-Type becomes ticket_type. The first value is available through values.<key> and duplicates through groups.<key>.

Email input
Order ID:
AZ-123
Order ID: AZ-456
Customer Name: Ada
Mapper output
{
  "order_id": "AZ-123",
  "order_ids": ["AZ-123", "AZ-456"],
  "item_values": ["AZ-123", "AZ-456", "Ada"]
}

Extract table cells without parsing table text yourself

Table extraction returns normalized rows, columns, lookup maps, cell metadata, and a rectangular text matrix. Routes can map a single cell, iterate rows, or pass selected table records downstream. The extract.tables helper supports TSV, pipe, ASCII, HTML table, and opt-in HTML grid sources.

Email input
Item    Qty    Total
Widget  2      $10.00
Gadget  3      $15.00
Mapper output
{
  "widget_qty": "2",
  "gadget_total": "$15.00",
  "row_totals": [
    { "key": "widget", "total": "$10.00" },
    { "key": "gadget", "total": "$15.00" }
  ]
}

Use recipes instead of starting from a blank parser

RecipeUse whenEmits
Reply-only payloadYou want the new reply without quoted history.reply_text, has_quoted_content, quoted_depth
All linksYou need normalized URLs and link labels from HTML or text.links[] with url, label, and source_element
Repeated DOM cardsA stable HTML sender template contains repeated cards or layout tables.items[] or named fields selected with CSS/XPath
View Custom JSON recipes

Normalize, redact, or trim before the JSON is emitted

Before the final mapper runs, route pipelines can apply transform steps. Use them to normalize HTML into text, remove fields, rewrite values, or strip attachments that should not affect the JSON your receiver gets.

StepUse it for
html_to_textConvert message HTML into deterministic plain text.
remove_fieldsRemove or clear selected message fields, headers, or attachment metadata.
replace_valuesSet subject, body, or header values from literals or small templates.
strip_attachments_ifRemove attachments that match MIME, size, or filename conditions.
View transform steps
Pipeline config
{
  "steps": [
    {
      "name": "html_to_text",
      "args": { "width": 0, "preserve_links": true, "keep_tables": true }
    },
    {
      "name": "map.generic_json",
      "args": {}
    }
  ]
}

Attachment metadata in JSON, file bytes on demand

MailWebhook includes attachment metadata in JSON so your receiver can decide what to do next. Attachment files are not embedded in the webhook body and generic JSON does not include file URLs. When your app needs the bytes, use the attachment URL API.

See attachment API details
Attachment metadata
{
  "id": "9f5a1ded-538d-4f5f-a7a9-d3eacf9e58a0",
  "filename": "invoice-1042.pdf",
  "content_type": "application/pdf",
  "size": 93259,
  "is_inline": false,
  "sha256": "059a0f5260487bbe663994de1fd641401fec76ac9f6bddfe5b53ae60d4bb2d86"
}
Fetch bytes later
GET /v1/messages/{message_id}/attachments/{attachment_id}/url

JSON output from the mailbox source you already use

MailWebhook can transform messages from Gmail, Microsoft 365/Outlook, IMAP, or hosted mailboxes into route-defined JSON. Pick the source that matches your workflow, then use the same generic or custom JSON mapping patterns.

Where structured email JSON pays off

Invoice intake

Extract vendor, subject, invoice IDs, attachment metadata, and table totals into accounting workflows.

Order and fulfillment emails

Convert order IDs, item rows, shipping links, and status labels into API events.

Support and customer replies

Capture only the new reply content and useful headers before creating a ticket or agent task.

Lead and CRM routing

Pull contact fields, sender domains, links, and form-like labels into a CRM payload.

AI agent inboxes

Give agents structured inbound email events without letting them parse raw MIME or hold mailbox credentials.

Operations alerts

Convert monitoring and vendor notification emails into compact alert payloads with priority fields.

Where MailWebhook fits

ApproachWhat you getWhere it breaks
DIY IMAP or provider API workerFull control over mailbox polling and parsing.You own MIME parsing, HTML cleanup, extraction, retries, signatures, storage, and observability.
Basic inbound parse webhookA parsed email payload posted to an endpoint.You often still map the payload into your real receiver contract after it arrives.
Parser mailbox toolsTemplate-oriented extraction workflows.Good for some business users, but less direct for developers who want route-level JSON and webhook contracts.
MailWebhookExisting mailbox intake plus generic or custom JSON mapping before delivery.Best fit when inbound email should become application events, not when you need a one-off file converter.
Create your first route

Your JSON is delivered as the webhook body

After the route pipeline emits JSON, MailWebhook sends that payload to your endpoint. Delivery includes idempotency and signature headers so your receiver can process events safely. For request headers, signature verification, endpoint setup, replay, and public API operations, use the Email Webhook API page.

Webhook request
POST /webhooks/email HTTP/1.1
Content-Type: application/json
X-Idempotency-Key: 6b8b7f9e...
X-MailWebhook-Signature: t=1782478472, kid=whsec_123, v1=...

Start free, scale when you need to

The Free plan includes 300 emails/month at no cost. Paid plans start at $29/per month with a 30-day free trial.

  • HMAC-signed webhook delivery
  • Automatic retries with backoff
  • Event inspector and replay
  • Idempotency keys for safe dedupe

Email to JSON FAQ

Can MailWebhook convert email to JSON?
Yes. MailWebhook converts matching inbound emails into JSON route outputs. Use the documented generic JSON shape or configure a custom JSON mapper for the fields your receiver needs.
Is this a one-off email file to JSON converter?
No. This page is about ongoing inbound mailbox workflows. MailWebhook receives messages from supported sources, transforms them in a route pipeline, and delivers JSON to your endpoint.
What is the default JSON schema?
The default mapper emits mailwebhook.generic@1 with top-level schema, event, message, body, meta, and optional envelope objects.
Can I create my own JSON shape?
Yes. Use map.custom_json to define ordered vars and an output template. The mapper config is schema-validated, and the emitted output can match the contract your receiver expects.
Can I extract fields such as order IDs or invoice numbers?
Yes, when those fields are present in the message body or HTML. Custom JSON routes can use key/value extraction, regex helpers, table extraction, DOM extraction, and normal message-field paths.
Can MailWebhook parse tables into JSON?
Yes. The extract.tables helper can return tables, row and column lookup maps, iterable rows and columns, and a text-only matrix for supported text and HTML table formats.
Are attachments included in the JSON?
Attachment metadata can be included in JSON. Attachment file bytes are not embedded in webhook bodies; fetch file bytes later through the attachment URL API when needed.
Can Gmail or Microsoft 365 email become JSON?
Yes. MailWebhook supports Gmail, Microsoft 365/Outlook, IMAP, and hosted mailbox workflows as sources, then maps matching messages into JSON through the same route pipeline.
Is this the same as an email webhook API?
It is related, but the intent is different. /email-to-json explains payload shaping and extraction. /email-webhook-api explains webhook request contracts, endpoint setup, signatures, idempotency, and public API operations.
Do I still receive a webhook?
Yes. For HTTP routes, the mapped JSON is posted to your endpoint as the webhook body.

Turn the next matching email into JSON your app can use

Create a route, choose the generic schema or custom mapper, and let MailWebhook deliver structured email data to your webhook endpoint.