# Send and parse email in one API

Source: https://developer.nylas.com/docs/cookbook/email/send-and-parse-email-api/

Most email tools pick a side. Transactional senders push outbound mail well but never read a reply. Inbound parsers receive mail at a webhook address but can't send the answer. Build a real workflow, like a support inbox that replies on its own or an app that ingests forwarded receipts, and you end up wiring two products together, reconciling two sets of IDs, and writing glue code to match an inbound message to the thread it belongs to.

This guide shows one integration that does both. You send with `POST /v3/grants/{grant_id}/messages/send`, read incoming mail with `GET /v3/grants/{grant_id}/messages`, and pull a clean body out of the noise with `PUT /v3/grants/{grant_id}/messages/clean`, all against the same grant and the same message schema. It's honest about when a send-only service is still the better pick.

## Which email API supports both sending and parsing in one integration?

The Nylas Email API handles sending, reading, and parsing through one grant and one JSON schema. You send with `POST /v3/grants/{grant_id}/messages/send`, list inbound mail with `GET /v3/grants/{grant_id}/messages`, and strip a body to clean text with `PUT /v3/grants/{grant_id}/messages/clean`. The same grant reaches 6 providers, including Google, Microsoft, and IMAP.

A send-only provider and a parse-only provider solve half the problem each. Stitching them together means two API keys, two billing relationships, and a mapping layer that ties an outbound message ID to the inbound reply that lands days later. With a single grant, a sent message and its reply share the same `thread_id`, so thread context comes for free. The table below compares the split-stack approach with the unified one.

| Task | Send-only + parse-only services | Nylas Email API |
| --- | --- | --- |
| **Send mail** | Transactional provider, its own API key | `POST /v3/grants/{grant_id}/messages/send` |
| **Read inbound mail** | Separate inbound-parse webhook | `GET /v3/grants/{grant_id}/messages` |
| **Clean body text** | Roll your own HTML stripping | `PUT /v3/grants/{grant_id}/messages/clean` |
| **Thread context** | Manual ID reconciliation across 2 systems | Shared `thread_id` on every message |
| **Provider coverage** | Per-service, often SMTP-only | Google, Microsoft, Yahoo, iCloud, IMAP, and more |

## How do I parse an email body in Python using an API?

Parse an email body in Python by calling `PUT /v3/grants/{grant_id}/messages/clean` with a `message_id` array. The endpoint returns each message with signatures, quoted replies, and open-tracking images removed, so you get only the meaningful text. Because `message_id` accepts up to 20 IDs per request, you parse a batch in one call instead of one round trip per message.

Raw email bodies arrive wrapped in nested HTML, "Sent from my iPhone" footers, and the full quoted history of the thread. Stripping that with regex breaks the moment a provider changes its markup. The clean endpoint does the heuristic parsing server-side, and it never modifies the stored message, so the original stays intact on the provider. Set `html_as_markdown` to `true` when the output feeds a language model, since markdown keeps headings and lists that plain text drops.

```python [parseEmail-Python SDK]
from nylas import Client

nylas = Client(api_key="<NYLAS_API_KEY>")

# Step 1: fetch the most recent inbound message
messages = nylas.messages.list(
    "<NYLAS_GRANT_ID>",
    query_params={"limit": 1, "unread": True},
)
message_id = messages.data[0].id

# Step 2: parse it down to a clean body
cleaned = nylas.messages.clean_messages(
    "<NYLAS_GRANT_ID>",
    request_body={
        "message_id": [message_id],
        "remove_conclusion_phrases": True,
        "ignore_images": True,
    },
)

print(cleaned.data[0].conversation)
```

## How can I extract structured data from incoming email and automate workflows?

Extract structured data by reading inbound mail with `GET /v3/grants/{grant_id}/messages`, cleaning each body with the clean endpoint, then passing that text to a language model that returns JSON. To trigger the flow automatically, register a webhook for the `message.created` event so the API notifies you the instant a message lands, with no polling.

A receipt parser is the classic case. A forwarded order confirmation arrives, the webhook fires, you fetch the message, clean it to remove the forwarding chrome, then prompt a model to pull the vendor, total, and date into fields your app stores. The read call accepts a `received_after` Unix timestamp filter, so a catch-up job after downtime only fetches new mail. Pair this with the same grant's send endpoint to reply with a confirmation, and the whole loop runs through one integration.

The request below lists unread messages received after a given timestamp. It uses the `fields` query parameter set to `standard` for the default payload, and caps results at 50 per page. Each returned message carries a `thread_id` you reuse when you reply.

```bash
curl --request GET \
  --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/messages?unread=true&received_after=1704067200&limit=50&fields=standard' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>'
```

For the model step that turns clean text into JSON fields, see [extract structured data from email](/docs/cookbook/ai/extract-data-from-email/). For the cleaning options in full, see [clean message HTML and quoted text](/docs/cookbook/email/clean-messages/).

## How do I send a reply on the same thread?

Send a reply by calling `POST /v3/grants/{grant_id}/messages/send` with a `reply_to_message_id` set to the inbound message you're answering. The API threads the reply correctly on the provider and reuses the original subject, so the conversation stays intact in the recipient's mailbox. The send endpoint works across all 6 providers with the same request body.

Because the inbound message and your outbound reply share a `thread_id`, you can fetch the whole conversation later with `GET /v3/grants/{grant_id}/messages?thread_id=<THREAD_ID>` and feed the ordered history to a model for context. The request below replies to a parsed message and turns on open and link tracking through the `tracking_options` object. Tracking is optional and adds a 1-pixel image plus rewritten links.

```bash
curl --request POST \
  --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/messages/send' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "subject": "Re: Your order #4815",
    "body": "Thanks, your refund is processing and lands in 3 to 5 business days.",
    "to": [{ "name": "Leyah Miller", "email": "leyah@example.com" }],
    "reply_to_message_id": "<MESSAGE_ID>",
    "tracking_options": { "opens": true, "links": true }
  }'
```

## When is a send-only service the right choice?

Use a dedicated transactional sender when your app only ever pushes outbound mail and never reads a reply. Password resets, one-time codes, and receipt blasts that route bounces elsewhere don't need inbound parsing or thread context. A send-only provider is purpose-built for raw throughput, so adding read features you'll never call buys nothing.

Everything changes once a reply matters. A support workflow, a reply-to-confirm flow, or any app that ingests forwarded mail needs to send, read, parse, and thread, and doing that across two products means reconciling IDs by hand. The unified grant collapses that into one schema, and the same connection reaches Gmail, Microsoft 365, and IMAP mailboxes, so a real human inbox works the same as a no-reply sender. For pure outbound at volume, see [send transactional email](/docs/cookbook/email/transactional-send/) before deciding.

## What's next

- [Extract structured data from email](/docs/cookbook/ai/extract-data-from-email/) to turn clean message text into JSON your app stores
- [Clean message HTML and quoted text](/docs/cookbook/email/clean-messages/) for every parsing option on the clean endpoint
- [Send transactional email](/docs/cookbook/email/transactional-send/) for high-volume outbound mail through a domain grant
- [Getting started with Nylas](/docs/v3/getting-started/) to create a project, connector, and your first grant