Email parsing API
An email parsing API turns a message a machine sent to a human — an order confirmation, an invoice, an enquiry, an alert — into the JSON your system actually wanted. This page is about what that job really involves, which parts are harder than they look, and what the four established products and MailMint each do about it. Every competitor figure on this page is sourced and dated.
What the job actually is #
“Parse an email” sounds like one step. In practice it is six, and the API you choose is really a decision about how many of them you want to own:
- Receive it. An address that accepts mail from the public internet, with an MX record, TLS and a queue that does not lose messages.
- Decode it. MIME, nested multiparts, quoted-printable, eight character sets, an HTML part that disagrees with the text part, and a quoted reply chain underneath the new content.
- Decide whether to trust it. SPF, DKIM and DMARC, computed on the message as received — not inferred afterwards from headers a forwarder rewrote.
- Extract the fields. The part everyone thinks is the whole job.
- Know when extraction went wrong. The part that decides whether you can automate the result or have to eyeball it.
- Deliver it, reliably. A signed webhook that retries, or a cursor you can poll without missing or double-processing anything.
Steps 1 to 3 and step 6 are unglamorous and largely solved — inbound-email vendors sell them cheaply, and one of them, Postmark, prices inbound email with base64 attachments at about $0.00165 a message. That number is worth holding on to, because it tells you what the market thinks MIME handling is worth. Anything a parsing vendor charges above it is being charged for steps 4 and 5.
The five parts that are harder than they look #
- Layout drift. Positional rules — “the value between Total: and the newline” — work until the sender ships a new template, and then they fail silently.
- Variable-row tables. An invoice with three line items and one with forty are the same email to a human and completely different to a parser. Ask what happens to row 26.
- Numbers with a nationality.
1.180,50is one thousand one hundred and eighty euros and fifty cents in Germany and something else entirely to a naive parser. - Knowing a value is wrong. An empty string and a confidently wrong string look identical downstream. This is the single most useful thing an API can tell you and almost nobody returns it.
- Prompt injection. Any product that pipes an attacker-controlled email body into a language model inherits this. Nobody has solved it; ask what structural mitigations exist, and treat parsed output as data rather than instructions.
Who sells what #
The four established products, and the one honest free option. Prices read from each vendor’s own pricing page or pricing endpoint on 29 August 2026 and re-checked on 30 August 2026; capability findings from their own help centres and published API schemas, 25 August 2026. Where a vendor publishes no figure, the cell is empty rather than guessed.
| Product | Entry price | Per unit | Reads email body | Reads PDF contents | Per-field confidence |
|---|---|---|---|---|---|
| MailMint | Free for 300/mo, then $9 for 5,000 | $0.0018 | Yes | Not yet | Yes, with evidence |
| Mailparser | $29.95/mo | $0.1198 per email | Yes | No | None |
| Parseur | Free for 20/mo, then €49 | €0.49 per page | Yes | Yes | Document-level only |
| Docparser | $39.00/mo | $0.39 per document | No | Yes | One arithmetic preset |
| Zapier Parser | Free | Uses Zap tasks | Yes | No | None |
The pattern in the last column is the interesting one, and we went looking for it rather than assuming it: across 363 vendor help-centre articles and two published API schemas, not one of the four returns a per-field confidence or a pointer to the text a value came from. That absence is what MailMint was built around.
Rolling your own #
This is a real option and it deserves a straight answer rather than fear. An inbound-email vendor plus a language model plus fifty lines of glue will parse emails, and if you run n8n, its own Information Extractor node does it with no code at all. For a single sender of plain text with no attachments, that is genuinely sufficient and free, and we will not win you.
What you take on is steps 2, 3, 5 and 6 above, forever: charset and multipart edge cases, quoted replies bleeding into fields, auth verdicts, retries and idempotency, and above all the calibration question — a model asked how confident it is will happily answer 0.95 about a purchase-order number it invented. A self-reported number is not a confidence. That is why ours is computed from checkable facts instead: whether the quoted evidence really appears in the message, whether an independent deterministic layer agreed, whether the arithmetic reconciles, whether the value coerced to its declared type. The model’s own opinion is one input, weighted least, and it can only lower a score.
The response shape #
One frozen shape for every message, whether it arrived at your inbound address or was posted to
POST /v1/parse: headers, body (text, HTML, stripped of the quoted
reply chain, with a detected language), attachments, auth with the SPF, DKIM
and DMARC verdicts, tables detected in the message, and fields — your
schema, filled in. Each field looks like this:
"total": {
"value": 31.50,
"confidence": 0.97,
"source": "rules+model",
"evidence": "Total: $31.50"
}
A field that could not be found is null — never invented, never a placeholder
string. A message with anything doubtful still arrives, with needs_review: true and flags
naming the field, so nothing is ever silently dropped. There are
thirteen field types and each one documents exactly what it coerces
to.
curl -X POST https://mailmint.app.mintapis.com/v1/parse \
-H "Authorization: Bearer $MAILMINT_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "subject": "Invoice INV-2291 from Acme Ltd",
"text": "Invoice INV-2291\nTotal: $31.50\nDue: Sep 8, 2026\n",
"schema": [ { "name": "invoice_number", "type": "string", "description": "the invoice number" },
{ "name": "total", "type": "number", "description": "grand total including tax" },
{ "name": "due_date", "type": "date", "description": "when payment is due" } ] }'
That call needs no inbound address, no DNS record and no account beyond a key, and it stores nothing.
Three ways to receive it #
- A signed webhook.
x-mailmint-signature: t=<unix>,v1=<hex>where the hex ishmac_sha256(secret, t + "." + rawBody). The timestamp is inside the signed string, so a captured request cannot be replayed. Retries are included on every plan, including Free. Worked verification in Node and Python. - A cursor you poll. The same feed the n8n trigger runs on, so you cannot miss or double-process a message.
- The n8n node — 11 actions and a trigger, on npm.
Price #
| Plan | Price | Parsed emails / month | Per email | Raw message kept |
|---|---|---|---|---|
| Free | $0, no card | 300 | — | 30 days |
| Starter | $9/mo | 5,000 | $0.0018 | 90 days |
| Pro | $29/mo | 25,000 | $0.00116 | 180 days |
| Scale | $99/mo | 150,000 | $0.00066 | 365 days |
Every plan, including Free, gets per-field confidence with the evidence span, the SPF/DKIM/DMARC verdicts, signed webhooks with retries, re-parse of stored mail and the n8n node. The paid plans buy volume and a longer retention window — never a better answer.
What we cannot claim #
MailMint has paying customers, but no customer logo, testimonial or case study is quoted without
permission, and there is no uptime history to quote you. Two things are missing and named rather than glossed over:
the contents of PDF attachments are not read yet (the extractor exists, it is not
wired into the pipeline). The n8n node is published in n8n’s verified registry and
installs on n8n Cloud and self-hosted n8n. Everything
else on this page is live and can be checked with one curl before you spend anything.
Try it against your own email #
The honest test is not a feature table, it is your own worst email. Take the message that your
current parser gets wrong, paste its subject and body into POST /v1/parse, and look at
the confidence numbers and the evidence spans on the fields it returns. It stores nothing, it needs
no address and no DNS record, and the free plan — 300 parsed emails a month, no card —
is enough to run a real low-volume workflow rather than only to look at one.