# Email threading in Gmail vs Outlook

Source: https://developer.nylas.com/docs/cookbook/email/threads/gmail-vs-outlook-threading/

Gmail and Outlook both group replies into conversations, but they build those conversations on different rules. If you read mail from both providers, threads that look identical in each web UI arrive with different identifiers, different folder behavior, and different grouping logic underneath.

The Nylas Email API flattens that difference. Both providers map to one `thread_id`, so your code reads a Gmail conversation and an Outlook conversation through the same endpoint and the same fields.


> **Info:** 
> **New to Nylas?** Start with the [quickstart guide](/docs/v3/getting-started/) to set up your app and connect a test account before continuing here.


## How do Gmail and Outlook thread email differently?

Gmail builds threads from the `References` and `In-Reply-To` headers plus the subject line. Outlook assigns each conversation a `ConversationId` internally and groups by subject, recipients, and reply headers together. The two also disagree on folders: a Gmail message can carry several labels at once, while an Outlook message lives in exactly 1 folder.

The table below maps the differences that affect how you read and display conversations.

| Aspect | Gmail | Outlook |
| --- | --- | --- |
| Conversation identifier | Gmail thread ID from `References` and subject | `ConversationId` assigned by Exchange |
| Grouping basis | `References`/`In-Reply-To` headers and subject | Subject, recipients, and reply headers together |
| Folders per message | Multiple labels at once | One folder at a time |
| Subject-only matching | Reinforced by headers | Rejected if participants differ |
| Nylas field | `thread_id` | `thread_id` |

Outlook's `ConversationId` tracks the actual reply chain, so two messages with the same subject but different participants stay in separate threads. Gmail leans on headers first and falls back to the subject.

## How does one API normalize Gmail and Outlook threads?

The API maps Gmail's thread ID and Outlook's `ConversationId` to a single `thread_id` field, so the same GET request returns conversations from either provider in one schema across all 5 provider families. You send a request to `/v3/grants/{grant_id}/threads`, and each thread comes back with the same fields no matter which provider backs the mailbox.

The request below lists the 5 most recent threads from a connected account. The response is identical in shape for Gmail and Outlook, so you write the rendering code once.

```bash
curl --compressed --request GET \
  --url "https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/threads?limit=5" \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json'

```

```json
{
  "request_id": "1",
  "data": [
    {
      "starred": false,
      "unread": true,
      "folders": ["CATEGORY_PERSONAL", "INBOX", "UNREAD"],
      "grant_id": "<NYLAS_GRANT_ID>",
      "id": "<THREAD_ID>",
      "object": "thread",
      "latest_draft_or_message": {
        "starred": false,
        "unread": true,
        "folders": ["UNREAD", "CATEGORY_PERSONAL", "INBOX"],
        "grant_id": "<NYLAS_GRANT_ID>",
        "date": 1707836711,
        "from": [
          {
            "name": "Nyla",
            "email": "nyla@example.com"
          }
        ],
        "id": "<MESSAGE_ID>",
        "object": "message",
        "snippet": "Send Email with Nylas APIs",
        "subject": "Learn how to Send Email with Nylas APIs",
        "thread_id": "<THREAD_ID>",
        "to": [
          {
            "email": "nyla@example.com"
          }
        ],
        "created_at": 1707836711,
        "body": "Learn how to send emails using the Nylas APIs!"
      },
      "has_attachments": false,
      "has_drafts": false,
      "earliest_message_date": 1707836711,
      "latest_message_received_date": 1707836711,
      "participants": [
        {
          "email": "nylas@nylas.com"
        }
      ],
      "snippet": "Send Email with Nylas APIs",
      "subject": "Learn how to Send Email with Nylas APIs",
      "message_ids": ["<MESSAGE_ID>"]
    }
  ],
  "next_cursor": "123"
}


```

For Node.js, Python, Ruby, Java, and Kotlin versions of this call, see the provider guides for [Gmail threads](/docs/cookbook/email/threads/list-threads-google/) and [Outlook threads](/docs/cookbook/email/threads/list-threads-microsoft/).

## What fields does a thread return?

Each thread object aggregates state from every message in the conversation, so you can render an inbox row without fetching messages one by one. The `latest_draft_or_message` field embeds the most recent message with its body, and true or false flags roll up across the thread. The table covers the fields you'll use most.

| Field | Description |
| --- | --- |
| `thread_id` | The normalized conversation ID, mapped from Gmail or Outlook. |
| `latest_draft_or_message` | The most recent message or draft, including its `body`. |
| `participants` | The union of all senders and recipients across the thread. |
| `snippet` | The first 100 characters of the last received message, HTML stripped. |
| `folders` | All folder or label IDs the thread's messages appear in. |
| `unread`, `starred`, `has_attachments` | `true` if any message in the thread matches. |
| `earliest_message_date`, `latest_message_received_date` | The conversation timeline as Unix timestamps in seconds. |

To get per-message read or starred state, fetch the individual [messages in the thread](/docs/cookbook/email/get-message-thread/) rather than reading the thread-level flags.

## Things to know about cross-provider threading

The `folders` array is where Gmail and Outlook diverge most in practice. A Gmail thread can list several labels because Gmail applies labels per message, while an Outlook thread spans Inbox, Sent Items, and other folders because one conversation includes both received and sent mail. To filter threads to a single folder on either provider, pass the `in` query parameter.

Two more details matter when you handle both providers. Outlook supports `starred` only on Exchange 2010 or later, so older servers won't return it. And because thread-level flags aggregate across messages, `unread` being `true` means at least 1 message is unread, not the whole conversation. The [Gmail threads guide](/docs/cookbook/email/threads/list-threads-google/) and [Outlook threads guide](/docs/cookbook/email/threads/list-threads-microsoft/) cover each provider's quirks in depth.

## How do I filter threads to a folder or label?

Pass the `in` query parameter with a folder or label ID to return only threads that have at least 1 message in that location. The same parameter works on both providers, but the IDs differ: Gmail uses label IDs like `INBOX` or a custom label, while Outlook uses folder IDs. A thread matches if any message in it sits in that folder.

This is how you build a folder-scoped view like "threads in Inbox" without pulling the whole mailbox. Because an Outlook conversation can span Inbox and Sent Items, filtering by `in=INBOX` still returns the full thread, and its `folders` array lists every folder the thread's messages touch.

## How do I search threads in Gmail vs Outlook?

Use the `search_query_native` parameter to run a provider-native search. Gmail accepts Gmail search operators, so a URL-encoded `subject:invoice` returns matching threads in 1 request. Microsoft accepts Graph `$filter` syntax instead. The API passes your query straight to the provider, so you get the same results the provider's own search returns.

Because the syntax is provider-specific, branch on the grant's provider when you build the query. For Gmail you write operator strings; for Outlook you write `$filter` expressions. The [search best practices guide](/docs/dev-guide/best-practices/search/) documents the supported operators per provider.

## FAQ

### Why do Gmail and Outlook thread counts differ for the same mailbox?

Gmail and Outlook draw thread boundaries differently. Gmail leans on the `References` headers and subject, while Outlook uses its internal `ConversationId`. The same set of messages can group into a different number of threads on each provider, especially when subjects repeat or reply headers are missing.

### Does changing the subject line break a thread?

On Outlook, a subject change usually keeps the conversation together because `ConversationId` tracks the reply chain. On Gmail, a significant subject change can split the thread, since Gmail weighs the subject alongside the headers. Test both providers if your app rewrites subject lines.

### Can a single thread span Gmail and Outlook accounts?

No. A `thread_id` is scoped to 1 mailbox on 1 provider. If you merge mail from several accounts into one view, group by your own conversation key rather than `thread_id`, because each provider assigns its own. See [build a unified inbox](/docs/cookbook/email/unified-inbox/).

## What's next

- [Get a message thread](/docs/cookbook/email/get-message-thread/) to fetch a single conversation by ID.
- [Reply to a thread](/docs/cookbook/email/threads/reply-to-a-thread/) to send a message into an existing conversation.
- [List Gmail threads](/docs/cookbook/email/threads/list-threads-google/) and [List Outlook threads](/docs/cookbook/email/threads/list-threads-microsoft/) for provider-specific behavior.
- [Threads API reference](/docs/reference/api/threads/) for every query parameter and response field.