Displaying Threads as Trees

The docs call out, in a couple places, that email threads are trees, not lists.

This makes sense. However, I can’t find any fields in the messages or threads APIs that allows you to actually reconstruct the tree structure.

  • There is no “parent message” or “child messages” fields, at least as far as I can tell
  • There is an in_reply_to field on the message API but it’s only for EWS, so not super helpful in my case
  • There’s reply_to but that’s just telling you who you should add to the to line of a reply
  • There’s the In-Reply-To MIME header but is not exposed as a first class attribute, may or may not be present (?), and may or may not match the Nylas message IDs.

Am I missing something? If the docs talk about this tree structure and have a whole diagram, it must be modeled somehow in the APIs, right?

I forgot to mention that it is more explicit on the messages.send API – there you do directly provide a reply_to_message_id

Hi,

Let me clarify what’s available and how to get what you need.

The short answer: The Thread object returns a flat message_ids array, and the in_reply_to field on messages is indeed EWS-only (not populated for Gmail, Microsoft Graph, or IMAP). There’s no parent_message_id or children field.

How to reconstruct the tree: Use fields=include_basic_headers on the Messages endpoint:

GET /v3/grants/{grant_id}/messages?thread_id={thread_id}&fields=include_basic_headers

This returns three RFC headers per message, just the ones needed for threading:

{
  "id": "msg_abc",
  "thread_id": "thread_123",
  "headers": [
    { "name": "Message-ID", "value": "<unique-id@mail.gmail.com>" },
    { "name": "In-Reply-To", "value": "<parent-id@mail.gmail.com>" },
    { "name": "References", "value": "<root-id@mail.gmail.com> <parent-id@mail.gmail.com>" }
  ]
}

This works across all providers (Google, Microsoft Graph, IMAP, EWS). From there you can build the tree:

  1. Map each message’s Message-ID header → Nylas message id

  2. Use In-Reply-To to find each message’s parent

  3. Messages without an In-Reply-To (or whose parent isn’t in the thread) are roots

A few things to keep in mind:

  • Nylas message id is different from the RFC Message-ID header, so you’ll need to maintain a mapping

  • Some messages may be missing In-Reply-To or References (not all email clients set them consistently)

  • You may need to paginate if the thread has many messages

We’ve filed a docs improvement ticket to make this clearer, the current wording around “tree structure” is conceptual but doesn’t explain how to actually retrieve the parent-child relationships. We’ll be updating the threads guide with explicit guidance on using include_basic_headers for tree reconstruction.

Let me know if you have any questions or run into issues with this approach!

Thanks, that’s clear. The docs update will be helpful to others who have this question as well.

Even better would be including this in the “normal” response body using the existing Nylas message IDs so that:

  • I don’t have to keep the mapping around
  • I don’t have to deal with edge cases like two messages in a Nylas thread having missing In-Reply-To (which one’s root:?), etc.

That’s a fair point, and I appreciate you thinking through the ideal developer experience here.

The reason we expose this through fields=include_basic_headers rather than resolving it automatically into Nylas IDs is that it gives you more control. Resolving parent message IDs behind the scenes would require additional calls to the email provider for every message returned, which adds latency and counts against provider rate limits, especially on list endpoints. We’d rather give you the building blocks and let you decide when and how to resolve those relationships, instead of silently slowing down every message response.

Feel free on filing a feature request with our Product team to express your interest and use case here: https://feedback.nylas.com.

Many thanks