Skip to content
Skip to main content

How to search email messages

Last updated:

You want to find a specific email across a user’s mailbox without pulling the whole inbox down first. The Messages API lets you search by envelope fields like subject, from, to, and any_email, or hand a provider its own native query string through search_query_native. The same request shape works across Gmail, Microsoft 365, Yahoo, iCloud, and IMAP.

This recipe focuses on search specifically: matching by metadata, running provider-native full-text queries, and the limits each provider imposes. For the full filter parameter table, see List Google messages.

How do I search email messages with the Nylas API?

Section titled “How do I search email messages with the Nylas API?”

Send a GET request to /v3/grants/{grant_id}/messages with search parameters such as subject, from, to, or any_email. The endpoint returns up to 200 matching messages per page in one unified schema across all 6 providers. For provider-native full-text search, pass a URL-encoded query through search_query_native instead.

The subject filter is case-sensitive and matches partial strings, so subject=invoice returns any message whose subject contains that word. The any_email parameter accepts up to 25 comma-separated addresses and matches the To, From, CC, or BCC fields. The request below searches a mailbox for invoice messages and limits the result to 5. It hits the same List Messages endpoint you use to page through an inbox.

The Nylas CLI runs the same search from your terminal: nylas email search matches a free-text query and layers on sender, date, and attachment filters, so you find specific mail without writing a query loop.

# Free-text search, restricted to one sender with attachments
nylas email search "invoice" --from [email protected] --has-attachment
# Any subject from one sender in a date window
nylas email search "*" --from [email protected] --after 2025-01-01 --before 2025-12-31

Search returns 20 results by default and pages through up to 200 messages once --limit goes over that. Search semantics are the provider’s, so Gmail’s operator-rich search behaves differently from a bare IMAP search. See the email search command reference for every filter.

Search by sender, recipient, or participant

Section titled “Search by sender, recipient, or participant”

Four envelope parameters cover most people-based searches: from matches the sender, to matches a recipient, any_email matches any of the To, From, CC, or BCC fields, and cc/bcc match those lists directly. The any_email parameter takes up to 25 addresses in one comma-separated request, which makes it the fastest way to find every message exchanged with a set of people.

These are server-side filters, so the provider does the matching and you get back only the messages that qualify. The request below finds messages exchanged with two people by passing both addresses to any_email. You’d reach for this when building a contact-history view or a per-customer email log.

You can combine these with received_after, received_before, unread, starred, and has_attachment to narrow further. For the complete 8-parameter filter reference, see List Google messages.

Run a full-text search with search_query_native

Section titled “Run a full-text search with search_query_native”

The search_query_native parameter accepts a URL-encoded, provider-specific query string and passes it straight to the underlying provider. This unlocks full-text search and operators that the standard parameters can’t express, across 4 providers: Google, Microsoft Graph, EWS, and IMAP. Each provider speaks its own query dialect, so the syntax inside the string changes per provider.

When you use search_query_native on Google or Microsoft, you can only combine it with 3 parameters: in, limit, and page_token. Any other query parameter returns a 400 error. The request below runs a Gmail search for messages whose subject contains “invoice” or “receipt”; the raw query subject:invoice OR subject:receipt is URL-encoded before it goes on the wire.

Search capability splits into two tiers. Standard parameters such as subject, from, to, and any_email behave consistently across all 6 providers. Native operators differ: Gmail uses search-box syntax, Microsoft Graph uses Keyword Query Language (KQL) or $filter, IMAP uses RFC 3501 SEARCH keys, and EWS uses Advanced Query Syntax. The table below maps a few common Gmail operators you can drop into search_query_native.

OperatorWhat it matchesExample
from:Messages from a senderfrom:[email protected]
to:Messages to a recipientto:[email protected]
subject:Subject line containssubject:invoice
has:attachmentHas file attachmentshas:attachment
after:Messages after a dateafter:2025/01/01
ORCombine conditionsfrom:alex OR from:priya

Provider dialects vary enough that one native query rarely ports across providers:

  • Google supports the Gmail search operators from the search box, like has:attachment and label:.
  • Microsoft Graph accepts both $search (KQL) and $filter queries such as $filter=from/emailAddress/address eq '[email protected]'.
  • IMAP, Yahoo, and iCloud accept any standard parameter alongside search_query_native, but some IMAP servers don’t implement the SEARCH command and return a 400 error.
  • EWS accepts every parameter except thread_id, and only works when the server administrator has enabled search indexing for all mailboxes.

For the full cross-provider breakdown, see the search best practices guide.

A handful of behaviors trip people up the first time they search at scale. None are obvious from the parameter list alone, so they’re worth calling out before you ship.

Subject matching is case-sensitive and partial

Section titled “Subject matching is case-sensitive and partial”

The subject parameter does a case-sensitive partial match, which means subject=Invoice and subject=invoice return different result sets. If you can’t predict casing, drop to search_query_native and let the provider’s full-text index handle case folding. Gmail and Microsoft both treat their native subject operators as case-insensitive, so subject:invoice matches “Invoice”, “INVOICE”, and “invoice” alike.

Standard filters search metadata, not body text

Section titled “Standard filters search metadata, not body text”

The standard parameters match envelope and header fields only. None of them search the message body. To match words inside the body, you need search_query_native with a provider that indexes content, such as Gmail ("meeting notes") or Microsoft $search. This is the single biggest reason a metadata search returns 0 results when the user swears the term is “in the email” somewhere.

Microsoft enforces mutually exclusive parameter groups

Section titled “Microsoft enforces mutually exclusive parameter groups”

On Microsoft Graph accounts, certain parameters can’t be combined. Group 1 (thread_id, unread, starred) and Group 2 (subject, to, cc, bcc, any_email) are mutually exclusive, so you can’t filter starred messages to a specific address in one request. Split it into two calls, or use search_query_native instead. This restriction is a Microsoft limitation, not a Nylas one.

A search returns the same cursor-based pagination as an unfiltered list. The default page size is 50 messages and the maximum is 200; pass the page_token from each response to fetch the next page. Filters stay applied across pages automatically, so you don’t re-send the search parameters on follow-up requests. For the paging pattern in code, see List Google messages.