Skip to content
Skip to main content

Read and parse incoming email

Last updated:

You connected a mailbox, and now you need what’s actually inside each email: who sent it, the subject line, the body text, and any files attached. Pulling that out of raw email yourself means wrestling with MIME boundaries, base64 blobs, and a dozen character encodings.

The Nylas Email API returns every message already parsed. One GET request gives you structured from, to, subject, body, and attachments fields across Gmail, Outlook, Yahoo, iCloud, and IMAP, so your code never opens a MIME parser.

How do I read an incoming email with an API?

Section titled “How do I read an incoming email with an API?”

Send a GET request to /v3/grants/{grant_id}/messages to read recent email from a connected account. The response returns each message as JSON with parsed from, subject, body, and attachments fields. There’s no fetch command and no MIME decoding step on your side.

The request below lists the 5 most recent messages from one mailbox using the limit query parameter. The endpoint returns 50 messages by default and up to 200 per page, so set limit deliberately when you only need the latest few.

The same request shape works for every provider. Swap the grant and you read Gmail, Outlook, or a self-hosted IMAP server through one schema.

What fields does a parsed message include?

Section titled “What fields does a parsed message include?”

Each message object carries the parsed headers and content you need to display or process email. Sender and recipient fields arrive as arrays of name and email pairs, the body comes back as a single string, and attachments are listed as metadata you fetch separately. The table below covers the fields you’ll use most.

FieldDescription
from, to, cc, bccArrays of { name, email } objects for each participant.
subjectThe message subject as a plain string.
bodyThe full message body as HTML or plain text, depending on the sender.
snippetA short preview of the body, useful for inbox list views.
dateSend time as a Unix timestamp in seconds (for example, 1706811644).
foldersThe folder or label IDs the message belongs to, such as INBOX.
thread_idThe ID of the conversation this message belongs to.
attachmentsMetadata for each file: filename, size in bytes, and content_type.
unread, starredTrue or false flags for read state and flag state.

Those 11 fields replace the headers, parts, and flags you’d otherwise extract from a raw message. To pull just one conversation, use the thread_id to fetch the full thread.

Why not parse MIME and email headers yourself?

Section titled “Why not parse MIME and email headers yourself?”

Raw email is a MIME document with nested multipart sections, per-part character sets, and content encoded as base64 or quoted-printable. Parsing it by hand with Python’s email module or a Node library means handling each encoding, telling inline images from real attachments, and surviving malformed messages from real senders.

MIME has accumulated quirks since RFC 2045 standardized it in 1996, and every provider bends the rules a little. A REST API does that decoding server-side and hands back clean fields, which is the main reason teams reach for one instead of an IMAP client. You trade some low-level control for not maintaining a parser against thousands of mailbox variations.

How do I get the readable text from a body?

Section titled “How do I get the readable text from a body?”

Message bodies often arrive as HTML stuffed with signatures, quoted replies, and tracking images. To strip that down to plain text or markdown, use the clean messages endpoint, which removes boilerplate and quoted history. It handles up to 20 messages in 1 request, so you can clean a batch before showing previews or feeding text to a language model.

The full request, options, and language samples live in the clean messages guide. Reach for it whenever the raw body field is too noisy to display or summarize directly.

Things to know about reading email content

Section titled “Things to know about reading email content”

A few practical details shape how the body and attachments fields behave in production. Most providers return HTML bodies, so plan to sanitize or render the markup rather than print it raw. The snippet field gives you a quick text preview without parsing the HTML at all.

The message lists attachments by metadata, not embedded bytes in the JSON. Each entry lists a size in bytes (the sample invite above is 2,504 bytes) and a content_type, and you fetch the binary content from the attachments endpoint when you need it. Inline images carry a content_id referenced from cid: URLs in the body. Dates are Unix timestamps in seconds, so multiply by 1,000 before passing them to a JavaScript Date.

Fetch one message with a GET request to /v3/grants/{grant_id}/messages/{message_id}. You get the same parsed object the list endpoint returns, scoped to a single email, with all 11 fields populated. Reach for it when you already hold a message ID from a webhook or an earlier list call and need the full body and attachments.

The request below fetches one message by its ID. The response is a single message object rather than an array, so there’s no data list to iterate.

A webhook is the usual source of that message ID. To get one whenever mail arrives, set up a new email webhook and read each message by the ID in the event payload.

How do I read only unread or recent messages?

Section titled “How do I read only unread or recent messages?”

Narrow the list with query parameters instead of pulling every message. The unread=true filter returns only unread mail, and received_after takes a Unix timestamp in seconds to fetch recent messages. Combine them with limit to cap the page at 10 messages. These filters run server-side, so you transfer less data over the wire.

The request below returns up to 10 unread messages received after a given timestamp, which is a common shape for an inbox sync loop.

You can also filter by from, to, subject, in (folder or label ID), and has_attachment. The Messages API reference lists every parameter and its accepted values.

Does the API decode base64 and quoted-printable for me?

Section titled “Does the API decode base64 and quoted-printable for me?”

Yes. The body field arrives already decoded, no matter how the original MIME parts were encoded. You never call a base64 or quoted-printable decoder yourself, which is the main thing a REST email API removes from your code.

It depends on what the sender sent, and most messages come back as HTML in the body field. Use the snippet field for a quick 100-character plain-text preview, or the clean messages endpoint to convert HTML to plain text or markdown.

No. The body holds text and HTML only. Attachments appear in the attachments array as metadata (filename, size in bytes, and content_type), and you download the bytes from the attachments endpoint when you need them.

The date field is a Unix timestamp in seconds, which is timezone-independent. Convert it to the user’s local time in your app. In JavaScript, multiply the value by 1,000 and pass it to new Date().