# What is an email parser?

Source: https://developer.nylas.com/docs/cookbook/email/what-is-an-email-parser/

You want an AI agent to read an inbox and do something useful: pull an order number off a receipt, flag a refund request, or route a vendor invoice to the right queue. The problem shows up the moment you fetch the first message. What comes back is raw MIME: nested multipart boundaries, quoted-printable encoding, an HTML body wrapped in tracking pixels, and a signature block longer than the message itself. None of that is data your code can act on yet.

That gap is what an email parser closes. This guide defines the term, shows where parsing sits in an agent pipeline, and walks through the read, clean, and extract steps using endpoints that already handle the MIME mess for you.

## What is an email parser and how does it fit into an AI agent pipeline?

An email parser is software that reads a raw email message and converts it into structured, predictable fields: sender, recipients, subject, a clean body, dates, and attachments. In an AI agent pipeline it sits at the front, between the inbox and the model. The agent can't reason over raw MIME, so the parser produces tidy text and JSON.

A typical pipeline has four stages, and parsing spans the first two. First you fetch the message through `GET /v3/grants/{grant_id}/messages`, which already returns parsed fields like `from`, `to`, `subject`, and `body` instead of a raw MIME blob. Second you clean that body to strip noise. Only then does stage three, the language model, run extraction, and stage four acts on the result. Skipping the parse step means feeding a model bytes it wasn't built to read, and email bodies often carry large HTML payloads once signatures and quoted history pile up.

## How does an AI-powered app use email parsing to extract structured data?

An AI-powered app uses email parsing in two passes. The deterministic pass parses the envelope and body into fields with code, since structure like the sender or subject never needs a model. The probabilistic pass sends the cleaned body to a language model to pull values that vary by message, like an invoice total.

Start with the read call. `GET /v3/grants/{grant_id}/messages` returns parsed messages across every connected provider in one JSON shape, so a single code path handles Gmail, Outlook, and iCloud. The `limit` parameter caps a page at 50 by default and 200 at most; set it to 20 when an inbox is busy to keep responses small. This request lists recent messages for one grant.

```bash
curl --request GET \
  --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/messages?limit=20' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>'
```

Each item in `data` already carries a parsed `from` array, a `subject` string, a `date` timestamp, and a `body`. The model never sees raw headers, so it spends tokens only on the content that actually needs interpretation.

## What is the difference between a contacts API and an email address parser?

A contacts API stores and retrieves people records you've saved, while an email address parser reads the address fields out of a single message. The contacts API answers "who do I know?" The parser answers "who sent this and to whom?" An extraction pipeline usually needs both: parse the message, then match the sender against saved contacts.

The read endpoint already parses address fields for you. `GET /v3/grants/{grant_id}/messages/{message_id}` returns a single message with `from`, `to`, `cc`, and `bcc` as arrays of `{name, email}` objects, so you don't write a regex against a raw `From:` header. Separately, `GET /v3/grants/{grant_id}/contacts` returns saved people, where the contact's address lives in an `emails` array. The table below maps the split, with the unified parse-and-extract path in the right column.

| Task | Contacts API | Email parser |
| --- | --- | --- |
| **Question answered** | Who is in my address book? | Who sent this message and what's in it? |
| **Input** | A grant's saved contacts | One raw email message |
| **Endpoint** | `GET /v3/grants/{grant_id}/contacts` | `GET /v3/grants/{grant_id}/messages/{message_id}` |
| **Address field** | `emails` array on a contact | `from` / `to` arrays, parsed for you |
| **Use in a pipeline** | Match a sender to a known person | Read, clean, and extract message content |

## How do I clean a parsed body before extraction?

Clean the body first because raw email carries signatures, quoted replies, tracking images, and "Sent from my iPhone" footers that waste tokens and confuse a model. Send `PUT /v3/grants/{grant_id}/messages/clean` with a `message_id` array, and the API returns each message with just the meaningful text. The field accepts up to 20 messages per request.

The call below cleans one parsed message, stripping signatures, quoted history, and tracking pixels so the model reads only the real content. Add the `html_as_markdown` beta flag if you want to keep headings and lists that plain text drops. Cleaning is heuristic, so spot-check the result on real mail before you trust it in production.

```bash
curl --request PUT \
  --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/messages/clean' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "message_id": ["<MESSAGE_ID>"],
    "ignore_images": true,
    "remove_conclusion_phrases": true
  }'
```

The response returns cleaned text without modifying the stored message, so the original stays intact on the provider. Feed that tidy output to your extraction step. For the full set of cleaning toggles and the markdown beta flag, see the [clean message HTML and quoted text](/docs/cookbook/email/clean-messages/) guide.

## When should you parse raw MIME yourself?

Parse raw MIME yourself when you need bytes the structured fields don't expose, like a custom header, a DKIM signature, or an exact attachment boundary for compliance work. Request it through the read call with `fields=raw_mime`, which returns the `grant_id`, `object`, `id`, and `raw_mime` fields per message. Otherwise, the parsed fields save you a MIME library.

Raw MIME is honestly the right call for a narrow set of jobs: archival systems that must store the original byte-for-byte, security tools inspecting headers, or migrations that replay messages verbatim. The tradeoff is real work. You decode quoted-printable and base64 parts, walk nested multipart trees, and normalize charsets, all of which the parsed path handles for you across 6 providers. Reach for `raw_mime` when you specifically need the envelope, not because the parsed body is missing something. For most agent pipelines, the parsed body plus the clean step is enough.

## What's next

- [Extract structured data from email](/docs/cookbook/ai/extract-data-from-email/) to turn a cleaned body into JSON with a language model
- [Clean message HTML and quoted text](/docs/cookbook/email/clean-messages/) for every cleaning toggle and the markdown output flag
- [Build an AI email triage agent](/docs/cookbook/agents/email-triage-agent/) to act on parsed and extracted messages
- [Getting started with Nylas](/docs/v3/getting-started/) to create a project, connector, and your first grant