# Email search for Agent Accounts

Source: https://developer.nylas.com/docs/v3/agent-accounts/email-search/

Use `search_query_native` to search an Agent Account's messages and threads by subject, participants, visible body text, and attachment filenames. Nylas runs the search before returning results, so your application doesn't need to download and index the mailbox itself.

> **Info:** 
> **This syntax applies to Agent Account grants with `provider: "nylas"`.** Connected grants use the native grammar of Google, Microsoft, EWS, or their IMAP provider. See [Searching with Nylas](/docs/dev-guide/best-practices/search/#search-messages-and-threads-using-search_query_native) for connected-provider syntax and restrictions.

## What Agent Account email search includes

One query searches the following content:

| Content      | What Nylas searches                                                                                                                                                                                                                                         |
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Subject      | The complete subject line. Subject matches have the strongest effect on relevance.                                                                                                                                                                          |
| Participants | Names and email addresses in `from`, `to`, `cc`, `bcc`, and `reply_to`.                                                                                                                                                                                     |
| Body         | The stored plain-text body. For an HTML-only message, Nylas indexes converted visible HTML text. When MIME includes a non-empty `text/plain` part, Nylas indexes that part. Visible quoted replies, signatures, and conversation history remain searchable. |
| Attachments  | Filenames that are visible to the Agent Account grant.                                                                                                                                                                                                      |

Separate terms can match in separate fields. For example, `charger alice@example.com` can match `charger` in the subject and `alice@example.com` in the participant list.

A quoted phrase must appear within one field or component. It can't start in the subject and finish in the body.

Email search doesn't inspect:

- Attachment contents.
- Raw MIME or raw headers.
- MIME Message-ID or attachment Content-ID values.
- Tracking or spam metadata.
- Participant labels such as the words `from` and `to`.

## Search messages

Send a [Get all Messages request](/docs/reference/api/messages/get-messages/) with `search_query_native`. The example below finds messages that contain `overdue` and either `invoice` or `receipt`, but excludes messages that contain `paid`.

When you make a direct HTTP request, URL-encode the query value. `curl --data-urlencode` handles characters such as spaces, parentheses, quotes, and `+`. Pass the raw query string to a Nylas SDK. The SDK encodes it for you.

```bash
curl --request GET \
  --url "https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/messages" \
  --get \
  --data-urlencode 'search_query_native=(invoice OR receipt) overdue -paid' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>'
```

```js [searchAgentMessages-Node.js SDK]
const messages = await nylas.messages.list({
  identifier: "<NYLAS_GRANT_ID>",
  queryParams: {
    searchQueryNative: "(invoice OR receipt) overdue -paid",
  },
});
```

```python [searchAgentMessages-Python SDK]
messages = nylas.messages.list(
  "<NYLAS_GRANT_ID>",
  query_params={
    "search_query_native": "(invoice OR receipt) overdue -paid"
  }
)
```

The response uses the standard Messages schema. Nylas doesn't add a relevance score to each object.

## Search threads

Use the same grammar with the [Get all Threads endpoint](/docs/reference/api/threads/get-threads/):

```bash
curl --request GET \
  --url "https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/threads" \
  --get \
  --data-urlencode 'search_query_native="payment failed" OR declined' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>'
```

A thread matches when at least one of its messages matches. Nylas returns each matching thread once and ranks it using its strongest matching message, rather than adding the scores of every matching message. The thread's latest-message snippet can differ from the older message that caused the match.

## Use the Agent Account query grammar

Agent Account search is case-insensitive and token-based. `AND` and `OR` are also case-insensitive when they appear outside quotes.

```text
query          := and_expression (OR and_expression)*
and_expression := unary_expression ((AND | whitespace) unary_expression)*
unary_expression := ["-"] primary
primary        := term | quoted_phrase | "(" query ")"
```

The grammar supports these building blocks:

| Syntax        | Behavior                                                      | Example                        |
| ------------- | ------------------------------------------------------------- | ------------------------------ |
| Term          | Match normalized searchable words, addresses, or identifiers. | `invoice`                      |
| Whitespace    | Require both expressions. Whitespace is an implicit `AND`.    | `invoice overdue`              |
| `AND`         | Require both expressions.                                     | `invoice AND overdue`          |
| Quoted phrase | Match adjacent terms in the specified order.                  | `"quarterly invoice"`          |
| `OR`          | Match either expression.                                      | `invoice OR receipt`           |
| Parentheses   | Group expressions and override normal precedence.             | `(invoice OR receipt) overdue` |
| Leading `-`   | Exclude a directly attached term, phrase, or group.           | `invoice -paid`                |

Operator precedence, from highest to lowest, is:

1. Terms, quoted phrases, and parenthesized groups.
2. A directly attached leading `-`.
3. Whitespace or explicit `AND`.
4. `OR`.

For example, `invoice OR receipt overdue` means `invoice OR (receipt AND overdue)`. Use `(invoice OR receipt) overdue` when `overdue` must appear with either alternative.

If you need to search for `and` or `or` as a literal word, quote it. For example, `research "and" development` requires all three literal terms.

`NOT` isn't an operator in Agent Account search. An unquoted `NOT` is an ordinary search term. Use a directly attached leading `-` to exclude an expression.

### Combine operators

| Query                                                            | What it matches                                                    |
| ---------------------------------------------------------------- | ------------------------------------------------------------------ |
| `invoice overdue`                                                | Messages that contain both terms.                                  |
| `"quarterly invoice" overdue -paid`                              | The phrase and `overdue`, excluding messages that contain `paid`.  |
| `invoice receipt OR payment declined`                            | Both `invoice` and `receipt`, or both `payment` and `declined`.    |
| `(invoice OR receipt) AND (overdue OR disputed)`                 | One term from each parenthesized group.                            |
| `"payment failed" OR "card declined"`                            | Either adjacent phrase, with its terms in order.                   |
| `invoice alice@example.com -paid`                                | All required terms across any searchable fields.                   |
| `(invoice OR receipt) AND (overdue OR disputed) -(paid OR void)` | One term from each positive group, excluding either negative term. |

### Negate terms, phrases, and groups

Attach `-` directly to the expression you want to exclude. A space after `-` is invalid.

These multi-word forms have different meanings:

| Query                   | Meaning                                                 |
| ----------------------- | ------------------------------------------------------- |
| `charger -(my book)`    | Exclude a result only when it has both `my` and `book`. |
| `charger -my -book`     | Exclude a result when it has either `my` or `book`.     |
| `charger -(my OR book)` | The same as `charger -my -book`.                        |
| `charger -"my book"`    | Exclude only the adjacent phrase `my book`.             |

Every possible match must still require a positive searchable term or phrase. Pure-negative queries such as `-resolved` and `-(resolved OR closed)` are invalid. An unanchored negative alternative such as `charger OR -resolved` is also invalid. Use `charger -resolved` instead.

## Combine full-text search with filters

For Agent Accounts, you can combine `search_query_native` with any other query parameter that the Messages or Threads endpoint supports for Agent Accounts. Nylas applies full-text search and structured filters using `AND`.

```bash
curl --request GET \
  --url "https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/messages" \
  --get \
  --data-urlencode 'search_query_native="quarterly invoice" -paid' \
  --data-urlencode 'from=billing@example.com' \
  --data-urlencode 'unread=true' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>'
```

Use structured parameters for field-specific conditions:

| Goal                                   | Use                                     |
| -------------------------------------- | --------------------------------------- |
| Search an address in any indexed field | `search_query_native=alice@example.com` |
| Require a specific sender              | `from=alice@example.com`                |
| Require a partial subject match        | `subject=quarterly invoice`             |
| Limit results to a folder              | `in=<FOLDER_ID>`                        |
| Require an attachment                  | `has_attachment=true`                   |

Don't put field prefixes inside the full-text query. For example, `search_query_native=from:alice@example.com` is invalid. Use `search_query_native=invoice&from=alice@example.com` to require a full-text match and that sender.

> **Info:** 
> **Thread filters keep their existing thread-level behavior.** The message that matches `search_query_native` doesn't have to be the same message that satisfies a structured filter. An original message could contain `invoice`, while a later reply in that thread satisfies `from=alice@example.com`.

## Understand relevance ordering

Adding `search_query_native` changes the result order from chronological to relevance order.

- Nylas considers term frequency, proximity, and the field where a match appears.
- Subject matches have the strongest weight.
- Participant names, participant addresses, and attachment filenames have more weight than body-only matches.
- Equal-rank messages use creation time and message ID for a stable order.
- Equal-rank threads use latest-message time and thread ID.
- Responses don't include the calculated relevance score.

If you need chronological results after a search, sort the returned objects in your application. Sorting each page locally doesn't create a globally chronological order across every result page.

## Paginate search results

Follow the response's `next_cursor` by passing it as `page_token` with the next request. Keep the endpoint, query, `limit`, filters, selected fields, and grant unchanged while you paginate.

Nylas binds each search page token to the original request. It returns a `400` response for these page-token mismatches:

- You omit `search_query_native`.
- You switch between Messages and Threads.
- You change a result-affecting parameter.
- You use a chronological page token for a relevance-ranked search.

Continue until `next_cursor` is absent. If a final page has exactly the requested number of objects, the following request can return an empty page without another cursor.

Search pagination isn't a snapshot. Editing a draft body or attachment can change an object's rank between requests, which can produce a duplicate or omission across pages. Restart without a `page_token` when you need a fresh traversal.

## Search limits

The Messages and Threads endpoints share these query limits. Query text uses Unicode Transformation Format 8 (`UTF-8`).

| Limit           | Behavior                                                                                                                                                   |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Query value     | Must contain valid `UTF-8` text after URL decoding and trimming. An empty value is invalid.                                                                |
| Query length    | At most 512 decoded `UTF-8` bytes. This is a byte limit, not a character limit.                                                                            |
| Expression size | At most 64 syntax-tree nodes, including terms, phrases, negations, `AND` groups, and `OR` groups. Parentheses don't add nodes.                             |
| Parentheses     | At most eight nested levels.                                                                                                                               |
| Searchable body | Nylas considers at most the first 2 MiB of visible body text. Token and index limits can make the searchable prefix shorter for an unusually long message. |

Invalid queries return a generic `400 Bad Request` response. Nylas rejects invalid syntax instead of ignoring it, including:

- Empty phrases or groups, unbalanced quotes or parentheses, dangling operators, and repeated operators.
- A term or phrase that has only punctuation and produces no searchable token.
- Field prefixes such as `from:`, `subject:`, or `in:`.
- Wildcards and prefixes such as `charg*`.
- Raw search operators such as `&`, `|`, `!`, and `<->`.
- A separated or repeated negation such as `charger - resolved` or `charger --resolved`.

Literal `:`, `*`, `&`, `|`, `!`, `<`, and `>` characters aren't supported in a full-text term or phrase. Email addresses remain supported. In a direct URL, encode an address's `+` sign as `%2B`. `curl --data-urlencode` does this automatically.

Broad queries, especially thread searches, can take more work than selective queries. If a search times out or the service is temporarily at capacity, Nylas returns a `503 Service Unavailable` response. Retry with backoff or narrow the query.

> **Warn:** 
> **Draft search refresh is best effort.** After a rare failed or racing draft body or attachment update, removed terms can still match and new terms might not match. A later successful content edit can refresh the search data. If no later edit occurs, including after you send the draft, the stale state can persist.

## What Agent Account search doesn't support

Agent Account search is token-based. It doesn't support:

- Typo tolerance. For example, `chargre` doesn't match `charger`.
- Arbitrary partial-token or prefix matching.
- Language-specific stemming. For example, `invoice` doesn't automatically match `invoices`.
- Semantic or vector similarity search.
- Attachment-content search.
- Gmail, Microsoft, EWS, or IMAP grammar emulation.
- A relevance score in the API response.

## What's next

- [Get all Messages reference](/docs/reference/api/messages/get-messages/) for every supported message filter and response field
- [Get all Threads reference](/docs/reference/api/threads/get-threads/) for every supported thread filter and response field
- [Email threading for agents](/docs/v3/agent-accounts/email-threading/) for how Nylas groups Agent Account messages into conversations
- [Searching with Nylas](/docs/dev-guide/best-practices/search/) for connected-provider search behavior