Search Threads with logical OR

Hello everyone!

I would like to filter threads using a search as described here: Nylas v3 Email, Calendar, and Contacts API docs | Nylas Docs

My use case is that a user will type their search string and this will be used to find the threads that either contain this in their subject or there is an email associated with that search string in the thread. After that the threads shall be returned from last to first.

I see I can use the columns “subject” and “any_email” which would serve my purpose quite well but there is not an option for a logical OR between the two. I can see that the ordering is by default that the latest thread should come first so in that aspect everything is ok.

I could see one solution being that I could make 2 separate requests in the same API, one with “subject” and another with “any_email” but there is an issue there in both ordering of the eventual response data and pagination.

Another solution I have considered for this is to use search_query_native and do something like the following: (I am using Microsoft provider)

filter_query = (
f"$filter=contains(subject,‘{search_string}’) or "
f"contains(from/emailAddress/address,‘{search_string}’)"
)

The problem with the above solution however is that results do not come ordered by latest date, and I can not seem to find a way to order them.

Any ideas?

Thanks a lot in advance :slight_smile:

Hello @gpapidas why don’t put the results in an array, make the date a date type and then sort the array the way you need it…I would do it that way :thinking:

That would unfortunately not work quite well. Here’s an example.

If we assume we are making 2 separate requests, one with subject and one with any email then we will get 2 separate responses.

Let’s assume that from the subject request the response is the following.

data = [{“value”: 1, “date”: Sep 5th}, {“value”: 2, “date”: Sep 4th}, {“value”: 3, “date”: Sep 3rd}] and then we have a page_token to go to page 2, where we would have values 4, 5 and 6 with dates Sep 2, Sep 1, August 31 respectively.

Now let’s say that in a similar manner my request with the “any_email” parameter has the following response.

page 1: data = [{“value”: 10, “date”: Sep 4th}, {“value”: 20, “date”: Sep 4th}, {“value”: 30, “date”: Sep 3rd}] and
page 2: data = [{“value”: 30, “date”: Sep 3rd}, {“value”: 40, “date”: Sep 2nd}, {“value”: 50, “date”: Sep 1st}]

now, if we combine the results of the first page and we want to serve 3 elements per page, we will serve, according to dates the following.

data = [{“value”: 1, “date”: Sep 5th}, {“value”: 2, “date”: Sep 4th}, {“value”: 10, “date”: Sep 4th}]

and that would probably work fine.

But what happens when the user wants to go to the second page?
How could I get the next correct set of data which would be the following

data = [{“value”: 20, “date”: Sep 4th}, {“value”: 3, “date”: Sep 3rd}, {“value”: 30, “date”: Sep 3rd}]

I mean, I could probably do something custom, but all the solutions I have thought involve creating a somewhat complex solution by keeping correct order from Nylas multiple API requests while also solving a problem of keeping 2 next_cursor values.

That’s why ideally I’d like to avoid this if possible.

Did you ever solve this?

Hey, I ended up storing the threads/emails into my own database and creating a custom search using tsvector/embeddings. If you follow this path, there is a rate limiting you’ll have to take into account if you try to sync historical emails of your users to your database.

I have not searched the documentation recently, but then there was no information about what this rate limiting is unfortunately. I had a call with Nylas support back then and they told me that it was 1 request every minute, but this is not true. I don’t remember the exact requests/minute I ended up doing, but you will need to experiment.

Generally, depending on what you are trying to build, you will find yourself wanting to store the threads/emails into your own database for a lot of cases.

Hope I helped even a little :slight_smile:

Hello,

The standard Nylas query parameters combine subject and any_email with AND logic, not OR. After digging into this, here’s what I found and the recommended solution.

For Microsoft provider, you can use search_query_native with native $search query syntax that supports OR:

import urllib.parse

search_string = "test"
search_query = f"subject:{search_string} OR from:{search_string} OR to:{search_string} OR cc:{search_string} OR bcc:{search_string}"
encoded_query = urllib.parse.quote(search_query)

# GET /v3/grants/{grant_id}/threads?search_query_native={encoded_query}

Regarding the ordering challenge, this is actually a Microsoft Graph API limitation, not a Nylas limitation. When using $search, Microsoft Graph returns results by “relevance” and doesn’t support combining it with $orderby. This is why your $filter approach with contains() also doesn’t work with ordering.

Since server-side ordering isn’t available with $search, here’s a practical pattern:

import urllib.parseimport requests

def search_threads_with_or(grant_id, search_string, api_key, page_size=50):# Build OR query for subject and email participants

search_query = (f"subject:{search_string} OR "f"from:{search_string} OR "f"to:{search_string} OR "f"cc:{search_string} OR "f"bcc:{search_string}")

encoded_query = urllib.parse.quote(search_query)

response = requests.get(
    f"https://api.us.nylas.com/v3/grants/{grant_id}/threads",
    params={
        "search_query_native": encoded_query,
        "limit": page_size
    },
    headers={"Authorization": f"Bearer {api_key}"}
)

data = response.json()
threads = data.get("data", [])
next_cursor = data.get("next_cursor")

# Sort by latest message date (client-side)
sorted_threads = sorted(
    threads,
    key=lambda t: t.get("latest_message_timestamp", 0),
    reverse=True
)

return sorted_threads, next_cursor

For pagination with proper ordering, you have two options:

Option 1: Fetch-and-Sort (Simpler)

  • Fetch larger batches (50-100 threads)

  • Sort client-side by latest_message_timestamp

  • Present smaller virtual pages to users

  • Use Nylas next_cursor to fetch more batches as needed

Option 2: Two-Request Merge (More Complex)

If you need precise pagination:

  1. Make parallel requests with subject and any_email separately

  2. Deduplicate by thread ID

  3. Sort the merged results

  4. Track both pagination cursors and implement virtual pagination

Option 1 is usually sufficient for most use cases and much simpler to implement.

Important Note

When using search_query_native with Microsoft provider, you can only combine it with in, limit, and page_token parameters no other filters are allowed.

Hope this helps! Let me know if you have questions about the implementation.

Many thanks,
Samuel R.
Support Engineer, Nylas