Email Parsing API

Parse EML and MBOX files to structured JSON. Headers, body, attachments, MIME parts — all as typed blocks. Deterministic, no AI needed.

Raw Email Is Noise

A typical email from Gmail or Outlook is 2,000+ lines of wire-format RFC 5322. MIME boundaries, base64-encoded attachments, folded headers across multiple lines, quoted-printable escape sequences. Feed that to an LLM and you're burning tokens on ARC-Seal: i=1; a=rsa-sha256; t=1775136695; cv=none; instead of the actual message.

AILANG Parse reads the RFC 5322 structure directly and outputs clean, typed blocks — the same format as DOCX, XLSX, and HTML parsing. Your pipeline handles email identically to every other format.

A 125 KB Google Cloud invoice email: 2,076 lines raw, 4 structured blocks. The parser extracts the message content, resolves the PDF attachment's text (with --deep), and maps Subject/From/Date to typed metadata — in under 2 seconds, with zero AI calls.

Raw .eml vs Structured Output

Raw .eml file (2,076 lines)
Delivered-To: user@company.com
Received: by 2002:ad4:5d67:0:b0:89c...
X-Received: by 2002:a53:c084:0:b0:650...
ARC-Seal: i=1; a=rsa-sha256; t=17751...
        d=google.com; s=arc-20240605;
        b=Htpf2+pNpdk7kEWo2yzUieUhVe...
         GUGJNZ20uHE4rPvnq0UW+8R1+v4...
ARC-Message-Signature: i=1; a=rsa-sha...
DKIM-Signature: v=1; a=rsa-sha256; ...
Content-Type: multipart/mixed;
  boundary="000000000000c91f7f064e77bbd9"

--000000000000c91f7f064e77bbd9
Content-Type: text/plain; charset="UTF-8"

Your monthly invoice is available.
...
--000000000000c91f7f064e77bbd9
Content-Type: application/pdf;
  name="5539333924.pdf"
Content-Transfer-Encoding: base64

JVBERi0xLjcKCjEgMCBvYmoKPDwgL1R5cG
UgL0NhdGFsb2cgL1BhZ2VzIDIgMCBSIC9N
YXJrSW5mbyA8PCAvTWFya2VkIHRydWUgPj
4gL1N0cnVjdFRyZWVSb290IDMgMCBSID4+
... (1,800+ more lines of base64)
Structured output (4 blocks)
{
  "metadata": {
    "title": "Your invoice is available",
    "author": "Google Payments",
    "created": "Thu, 02 Apr 2026 03:33:38 -0700"
  },
  "blocks": [
    {
      "type": "section",
      "kind": "email-headers",
      "blocks": [
        {"type": "text", "style": "email-header",
         "text": "From: Google Payments <payments-noreply@google.com>"},
        {"type": "text", "style": "email-header",
         "text": "To: user@company.com"},
        {"type": "text", "style": "email-header",
         "text": "Subject: Your invoice is available"}
      ]
    },
    {
      "type": "text",
      "style": "Normal",
      "text": "Your monthly invoice is available.
        Please find the PDF attached..."
    },
    {
      "type": "text",
      "style": "attachment",
      "text": "[attachment: 5539333924.pdf,
        application/pdf]"
    }
  ]
}

What Gets Extracted

Headers → Structured Metadata

Subject maps to title, From to author, Date to created. Multi-line folded headers (RFC 5322 §2.2.3) are automatically unfolded into single values.

Body Text

Plain text bodies become TextBlock. For multipart/alternative emails, both text and HTML parts are extracted as separate blocks.

MIME Multipart

Multipart/mixed (body + attachments), multipart/alternative (text + HTML), and nested multipart structures are all resolved by boundary splitting.

Attachments — Parsed Inline

Text-based attachments (CSV, HTML, Markdown, nested EML) are decoded and parsed inline as SectionBlock with kind attachment. With --deep, PDF and Office attachments are resolved too — PDFs with an automatic OCR fallback. Images are identified by filename and MIME type. See details below.

Encoding Support

Real-world email uses three encoding layers. AILANG Parse handles all of them:

EncodingRFCWhat It DoesExample
Base64 RFC 2045 §6.8 Body or attachment encoded as ASCII VGhpcyBpcyBiYXNlNjQ= → "This is base64"
Quoted-Printable RFC 2045 §6.7 Non-ASCII chars as =XX hex pairs =C3=A9 → é   =C3=BC → ü
Encoded-Words RFC 2047 Non-ASCII in headers (Subject, From) =?UTF-8?B?5Lya6K2w?= → 会議の議事録

Multi-byte UTF-8 sequences spanning consecutive =XX pairs are accumulated and decoded together — accented characters (café, résumé, Zürich), CJK, and emoji all work correctly.

MBOX Archives

MBOX files (RFC 4155) contain multiple emails separated by From  envelope lines. AILANG Parse splits them into individual messages, each wrapped in a SectionBlock with kind mbox-message. Every message gets full header/body/attachment parsing.

This makes MBOX ideal for bulk email processing: export a Gmail label or Thunderbird folder as MBOX, parse it in one call, and get structured JSON for every message in the archive.

Attachment Chain Parsing

Emails are documents that contain other documents. A budget email has a CSV; a contract email has HTML or a forwarded .eml. AILANG Parse decodes and parses text-based attachments inline — one API call extracts the email and its attachment content.

Supported inline formats: CSV, TSV, HTML, Markdown, plain text, and nested EML (message/rfc822). With the --deep flag, PDF, DOCX, PPTX, and XLSX attachments are also extracted and parsed. Image attachments are identified by filename and MIME type.

PDF attachments resolve as of v0.26.0. Measuring a real 65,000-message archive found 8,323 attachments, of which 2,455 were PDF and zero were DOCX, XLSX or PPTX. Until v0.26.0 the resolver preserved bytes only for OOXML — so the most common attachment type in real mail contributed its filename and not one word of its contents.
{
  "type": "section",
  "kind": "attachment",
  "blocks": [
    {"type": "text", "style": "attachment-meta",
     "text": "revenue_q1.csv (text/csv)"},
    {"type": "table",
     "headers": [{"text": "Region"}, {"text": "Revenue"}, {"text": "Target"}],
     "rows": [
       [{"text": "EMEA"}, {"text": "125000"}, {"text": "110000"}],
       [{"text": "APAC"}, {"text": "143000"}, {"text": "130000"}]
     ]}
  ]
}

With --deep, PDF and Office attachments get the same treatment — a DOCX attachment is decoded, extracted, and parsed into paragraphs and tables:

# Parse email + resolve Office attachments
ailang run --entry main --caps IO,FS,Env \
  docparse/main.ail invoice-email.eml --deep
{
  "type": "section",
  "kind": "attachment",
  "blocks": [
    {"type": "text", "style": "attachment-meta",
     "text": "q1_revenue.docx (application/vnd...wordprocessingml.document)"},
    {"type": "text", "text": "Q1 Revenue Analysis", "style": "Normal"},
    {"type": "table",
     "headers": ["Region", "Revenue"],
     "rows": [["EMEA", "$125,000"], ["APAC", "$143,000"], ["Americas", "$157,000"]]}
  ]
}

PDF Attachments — With Automatic OCR

PDF attachments resolve through a backend ladder that escalates only when it has to. pdftotext runs first: free, roughly instant, and correct for any born-digital PDF. If it comes back empty — the signature of a scanned or photographed document — the parser escalates to docling, a local OCR pass.

TierCostSpeedHandlesAutomatic?
pdftotextFree~0sBorn-digital text layerYes — default
doclingFree~9sScans, photos (local OCR)Yes — on empty result
aiPaidVariesHardest layoutsNever — opt in explicitly

Both automatic tiers are free, which is why escalation needs no permission. The ai backend costs money, so it is never entered on your behalf — a parser that silently spends is the wrong default. An explicit --pdf-backend choice is always respected rather than overridden.

Verified on an email carrying the same contract twice — once digital, once rasterised. Both yield "The Seller shall indemnify the Buyer against all claims"; the second purely via OCR. Note that liteparse is not an OCR tier: it infers headings from font sizes in the existing text layer, so it fails on scans exactly as pdftotext does.

An unreadable attachment never aborts the run. One bad file in a mailbox is not a reason to abandon the message — or, in batch mode, the remaining files.

Forwarded emails (message/rfc822 attachments) are parsed recursively — the inner email gets full header and body extraction, nested inside the attachment block.

Thread Reconstruction

Individual emails are often unintelligible without their thread. AILANG Parse reconstructs conversation threads from MBOX archives using Message-ID, In-Reply-To, and References headers.

# Threaded mode: groups messages into conversations
ailang run --entry main --caps IO,FS,Env \
  docparse/main.ail archive.mbox --threaded

Output: each thread becomes a SectionBlock with kind thread, containing the normalized subject, participant list, and chronologically-ordered messages with quoted text stripped.

{
  "type": "section",
  "kind": "thread",
  "blocks": [
    {"type": "text", "style": "thread-subject", "text": "Q2 Budget Planning"},
    {"type": "text", "style": "thread-participants", "text": "Alice, Bob, Carol"},
    {"type": "section", "kind": "thread-message", "blocks": [...]},
    {"type": "section", "kind": "thread-message", "blocks": [...]},
    {"type": "section", "kind": "thread-message", "blocks": [...]}
  ]
}

Thread reconstruction gives LLMs the full conversation context for summarization, triage, or automated response — without the noise of repeated quoted text.

Use Cases

Emails are documents that contain other documents. Structured parsing makes them composable with the rest of your data pipeline.

AI Email Triage & Routing

Feed structured email JSON to an LLM for classification, routing, or auto-response. A 2,000-line raw email becomes 4 typed blocks — the model reasons about content, not DKIM signatures. Classification accuracy improves because tokens are spent on the actual message, not transport headers.

Inbox Monitoring Agents

An AI agent watching a mailbox (IMAP, local .eml files, or Gmail API exports) parses each email to structured JSON, extracts the message + attachment manifest, and takes action. The agent sees [attachment: invoice.pdf, application/pdf] — not 1,500 lines of base64.

Email-to-Knowledge-Base

Parse MBOX exports from Gmail labels or Thunderbird folders into structured blocks, embed them in a vector database. Metadata (author, date, subject) becomes filterable dimensions alongside semantic search on body content. One ailang run --batch call processes an entire archive.

Multi-Format Document Pipelines

CSV, HTML, and Markdown attachments are parsed inline automatically. A single API call returns the email body and the table data from the attached spreadsheet — no second parse step needed. With --deep, PDF and Office attachments are resolved in the same pass, scanned PDFs included via local OCR.

Compliance & E-Discovery

Bulk MBOX processing with the full delivery chain preserved (Received headers, DKIM, SPF results) for forensic analysis, while body content is cleanly separated for legal review. Attachment manifests provide a complete inventory without extracting binary data.

Customer Support Automation

Parse inbound support emails to extract the customer query, thread context, and any attached screenshots or documents. The structured output feeds directly into ticket creation, sentiment analysis, or automated response generation — with the original email metadata preserved for routing.

Batch mode: ailang run --batch compiles once and parses N files, so the AILANG runtime startup is paid once per batch instead of once per file. Useful for processing entire mailbox directories in a single invocation.

Example: GitHub Notification

A real GitHub Actions notification email (48 KB, multipart/alternative with DKIM/ARC/SPF headers):

{
  "metadata": {
    "title": "[sunholo-data/ailang] Run failed: Build and Release - dev",
    "author": "\"Voight-Kampff (bot)\"",
    "created": "Thu, 02 Apr 2026 06:31:33 -0700"
  },
  "blocks": [
    {
      "type": "section",
      "kind": "email-headers",
      "blocks": [
        {"type": "text", "style": "email-header",
         "text": "From: \"Voight-Kampff (bot)\" <notifications@github.com>"},
        {"type": "text", "style": "email-header",
         "text": "Subject: [sunholo-data/ailang] Run failed: Build and Release - dev"},
        {"type": "text", "style": "email-header",
         "text": "X-Github-Reason: ci_activity"}
      ]
    },
    {
      "type": "text",
      "style": "Normal",
      "text": "Repository: sunholo-data/ailang\nWorkflow: Build and Release\nDuration: 5 minutes and 50.0 seconds\n\nJobs:\n  * Build ubuntu-latest succeeded\n  * Build windows-latest failed (2 annotations)\n  * Create Release Bundle skipped"
    }
  ]
}

28 raw headers (DKIM chains, ARC seals, SPF results) reduced to the headers that matter. The body is clean text, ready for an LLM to reason about build failures.

Try It

CLI

# Parse an EML email file
ailang run --entry main --caps IO,FS,Env \
  ~/.ailang/cache/registry/sunholo/ailang_parse/*/docparse/main.ail inbox.eml

# Parse an MBOX archive (multiple messages)
ailang run --entry main --caps IO,FS,Env \
  ~/.ailang/cache/registry/sunholo/ailang_parse/*/docparse/main.ail archive.mbox

API

curl -X POST https://docparse.ailang.sunholo.com/api/v1/parse \
  -H "Content-Type: application/json" \
  -d '{"filepath":"sample_eml_welcome","outputFormat":"markdown","apiKey":"YOUR_API_KEY"}'

Python SDK

from ailang_parse import DocParse

client = DocParse(api_key="YOUR_API_KEY")
result = client.parse("inbox.eml", output_format="json")

# Metadata extracted from headers
print(result.metadata.title)   # Subject line
print(result.metadata.author)  # From display name

# Iterate blocks like any other format
for block in result.blocks:
    if block.style == "attachment":
        print(f"Attachment: {block.text}")

Parse in Browser    API Reference

Frequently Asked Questions

How do I parse an EML file to JSON?

Send the .eml file to the AILANG Parse API or use the Python/JS/Go SDK. The parser returns structured JSON with typed blocks for headers, body text, HTML content, and attachments.

Does email parsing require AI or an API key?

No. Email parsing is fully deterministic — RFC 5322 and MIME spec parsing, not AI. It runs in the browser via WASM or server-side with zero external dependencies.

What email encodings are supported?

Base64 body decoding, quoted-printable (including multi-byte UTF-8), and RFC 2047 encoded-words for international headers (both B and Q encoding).

Can I parse MBOX archives with multiple messages?

Yes. MBOX files are split on RFC 4155 envelope lines. Each message becomes a separate section block, parsed independently with full header and body extraction.

What is the output format for parsed emails?

The same Block ADT used for DOCX, XLSX, and HTML parsing: typed blocks with metadata. Downstream code handles all formats identically. See the docs for the full schema.

Are email attachments parsed automatically?

Text-based attachments (CSV, HTML, Markdown, nested EML) are parsed inline automatically. With the --deep flag, PDF, DOCX, PPTX, and XLSX attachments are also extracted and parsed. PDF attachments use a free backend ladder: pdftotext first, escalating automatically to local OCR (docling) when the PDF has no text layer — a scanned contract, say.

Can I reconstruct email threads from an MBOX file?

Yes. Use the --threaded flag. Messages are grouped into conversation threads using Message-ID/In-Reply-To/References headers, with quoted text stripped from replies.