Every email provider speaks a different dialect. Gmail has labels and the Gmail API; Microsoft 365 has folders and Graph; Yahoo and iCloud want IMAP with app passwords; Exchange wants EWS. Build email into your product the obvious way and you end up maintaining four or five integrations that drift apart over time, each with its own auth, its own pagination, and its own quirks.
The Nylas Email API collapses that into one interface. You connect a user's mailbox once, get a grant_id, and from then on every message, thread, folder, and attachment comes back in the same shape no matter who hosts the mailbox. This post is a working tour of that surface from two angles: the HTTP API for your backend, and the Nylas CLI for the terminal, scripts, and quick experiments.
I work on the CLI, so the terminal examples below are the exact commands I reach for.
I'll cover the operations you actually reach for day to day — list, read, search, send, reply, and draft — and call out the provider differences worth knowing.
The grant: one connection, every provider
A grant is an authenticated connection to a single user's mailbox. You create it once through an OAuth flow (or Bring Your Own Auth), and Nylas hands you a grant_id that you pass on every request. That ID is the only provider-specific thing you deal with — the rest of the API is identical across Gmail, Microsoft 365, Exchange, Yahoo, iCloud, and IMAP.
Because the grant abstracts the provider, code you write against one mailbox works unchanged against all of them. A GET /messages against a Gmail grant and the same call against an iCloud grant return the same JSON fields. See the Email API overview for the full concept map of messages, threads, folders, and attachments.
Before you begin
You need a Nylas API key and at least one connected account. The fastest setup is the CLI:
nylas init # creates an account and generates an API key
nylas auth login # connect a mailbox over OAuth and store its grant
After nylas auth login, the CLI stores the grant as your default account, so every nylas email command below runs against it without you passing an ID. List what's connected anytime with nylas auth list. For the full authentication flow your app uses in production — OAuth scopes, redirect URIs, hosted auth — see the authentication docs.
List and read messages
Reading mail is the first thing most integrations do. The CLI lists your inbox in one command and defaults to the 10 most recent messages from INBOX only:
# 10 most recent inbox messages
nylas email list
# Only unread, from a specific sender
nylas email list --unread --from boss@company.com
# Everything across all folders, paginated automatically
nylas email list --all --max 500 --all-folders
The --all flag walks pagination for you and --max caps the total, which matters because a busy mailbox can hold hundreds of thousands of messages. Full flag reference lives at email list.
The same operation over HTTP is a GET against the grant's messages collection. The default page size is 50 and the maximum is 200; pass the next_cursor value from each response back as the page_token query parameter to fetch the next page:
curl --request GET \
--url "https://api.us.nylas.com/v3/grants/<GRANT_ID>/messages?limit=5&unread=true" \
--header "Authorization: Bearer <NYLAS_API_KEY>"
To open a single message and mark it read in one step:
nylas email read <message-id> --mark-read
The GET /messages reference lists every query parameter — sender, recipient, subject, unread state, starred, thread, and received-date ranges — so you can filter server-side instead of pulling everything and filtering in your app.
Search your mailbox
Filtering by exact fields covers a lot, but sometimes you need a free-text query. The CLI's search runs a query string against the provider's own search engine and layers structured filters on top:
# Free-text subject and body search
nylas email search "project update"
# Any subject from one sender, with attachments, in a date window
nylas email search "*" --from "hr@company.com" --has-attachment \
--after 2024-01-01 --before 2024-12-31
Using * as the query with a --from filter is the idiom for "every message from this sender regardless of content." The email search command documents the --in, --to, --subject, and --starred filters. Search returns 20 results by default, and only auto-paginates across multiple pages once you raise --limit above 200.
One thing worth knowing: search semantics are the provider's, not Nylas's. Gmail's search is more forgiving and operator-rich than a bare IMAP search, so the same query can return slightly different relevance across providers. For deterministic results, prefer the structured filters on GET /messages over free-text search.
Send email
Sending is one request, and the recipient sees a normal message from the connected mailbox — sent through the user's own provider, landing in their real Sent folder. From the CLI:
nylas email send \
--to user@example.com \
--subject "Hello from Nylas" \
--body "This went out through the connected mailbox."
The same call over HTTP hits POST /messages/send. The request body accepts to, cc, bcc, subject, body, from, reply_to, attachments, and more:
curl --request POST \
--url "https://api.us.nylas.com/v3/grants/<GRANT_ID>/messages/send" \
--header "Authorization: Bearer <NYLAS_API_KEY>" \
--header "Content-Type: application/json" \
--data '{
"subject": "Q3 report",
"body": "<p>Attached is the report.</p>",
"to": [{ "email": "finance@example.com", "name": "Finance" }],
"cc": [{ "email": "lead@example.com" }]
}'
A few capabilities that turn a basic send into a production one:
-
Scheduled send. Pass a
send_atUnix timestamp in the API, or use the CLI's human-friendly--scheduleflag:nylas email send --to a@b.com --subject Hi --body "later" --schedule "tomorrow 9am". Manage queued sends withnylas email scheduled list. -
Open and link tracking. Set
tracking_optionsin the request, or--track-opensand--track-linkson the CLI, to record when recipients open mail or click links. See message tracking for how the pixel and link-rewrite work. - Idempotent send. Retrying a failed send risks sending twice. Nylas supports an idempotency key so a retried request is de-duplicated server-side — see idempotent send.
The CLI's email send command also supports GPG signing and encryption and hosted templates, which are handy for transactional mail that needs consistent branding.
Reply and keep the thread intact
A reply is not just a send with Re: in the subject. To make mail clients group the reply with the original conversation, you have to set the in-reply-to relationship. The API field is reply_to_message_id; set it to the message you're answering and Nylas wires up the threading headers.
The CLI's reply command does this for you. It fetches the original to populate the recipient and subject, preserves threading through reply_to_message_id, and replies only to the original sender unless you add --all:
# Reply to the sender, in-thread
nylas email reply <message-id> --body "Sounds good, thanks!"
# Reply to everyone on the thread
nylas email reply <message-id> --all --body "Looping everyone in."
This is the biggest correctness trap in email integrations: send a "reply" without the threading header and it shows up as a brand-new conversation, which looks broken to the recipient. Always thread your replies. For how threads behave across providers — Gmail groups by conversation, others by header chain — see email threading explained.
Compose drafts before sending
When a human (or an approval step) reviews mail before it goes out, draft first and send later. Drafts persist server-side in the user's mailbox, so they sync to the provider's Drafts folder and show up in the user's normal mail client too:
nylas email drafts create --to user@example.com --subject "WIP" --body "Draft body"
nylas email drafts list
nylas email drafts send <draft-id>
The Drafts API mirrors this — create, update, list, and send — and the CLI commands are documented at email drafts create and email drafts send. Drafting is also the right pattern for an AI agent that proposes replies: generate the draft, route it through human approval, then send the approved draft by ID.
Handle attachments
Attachments ride on the message object as metadata; you download the bytes separately by attachment ID. Nylas accepts up to 25 MB inline through multipart on send, or up to 150 MB for Microsoft grants through the attachment-uploads flow. From the CLI:
nylas email attachments list <message-id>
nylas email attachments download <attachment-id> <message-id> --output ./file.pdf
The size ceiling is the one provider difference you can't ignore here: a 40 MB attachment that sails through a Microsoft grant will be rejected on a provider capped at 25 MB. Check the limit before you build a feature around large files. See attachments for the upload-session flow.
Limits and provider notes
| Dimension | Value | Notes |
|---|---|---|
| Default page size | 50 messages | Maximum 200 per page; use page_token to paginate |
| Inline attachment size | 25 MB | Up to 150 MB for Microsoft grants via upload sessions |
| Providers | Gmail, Microsoft 365, Exchange, Yahoo, iCloud, IMAP | One schema across all of them |
| Folders vs labels | Provider-specific | Gmail models folders as labels, so a message can be in several at once |
These are the defaults you'll hit first; rate limits and quotas vary by provider and plan. Gmail in particular enforces its own per-user sending and API quotas underneath Nylas — see Gmail API quotas before you scale outbound volume.
Wrapping up
The win with the Email API is that you write the integration once. List, search, send, reply, and draft are the same five calls whether the mailbox is Gmail or IMAP, and the CLI gives you the same operations in the terminal for testing and automation before you commit them to code. The provider differences that remain — search relevance, attachment ceilings, folders-as-labels — are few enough to enumerate, which is the whole point.
Where to go next:
- Email API overview — the full concept map and capabilities
- Send a message and list messages — endpoint references
-
Nylas CLI command reference — every
nylas emailsubcommand - Email threading explained — keep replies in the right conversation
Written by Qasim Muhammad and Pouya Sanooei.

Top comments (0)