Skip to content
Skip to main content

Build recipient autocomplete

Last updated:

Type two letters into Gmail’s “To:” field and it suggests the right person before you finish their name. Users now expect that everywhere, and a blank compose box with no suggestions feels broken. Building it per provider is the painful part: Google’s People API and Microsoft Graph each have their own auth, paging, and field names, and neither one covers the other’s contacts.

The Nylas Contacts API returns supported provider address books through one endpoint with one schema. You pull contacts once, cache them, and filter on the client as the user types. The same pattern works for Google, Microsoft, Exchange, hosted IMAP, native iCloud, and native Yahoo grants.

How do I build recipient autocomplete from contacts?

Section titled “How do I build recipient autocomplete from contacts?”

Recipient autocomplete is a 3-step pattern: fetch the user’s contacts once, cache them in memory, then filter that cache by prefix on every keystroke. You hit the API a handful of times at load, not once per character, so suggestions render in under a millisecond instead of waiting on a network round trip for each letter typed.

The steps below map directly to the sections in this recipe:

  1. Fetch all contacts from the Contacts API and page through the results.
  2. Cache them in a flat list of { name, email } entries keyed for fast prefix matching.
  3. Filter that cache as the user types, delaying input processing so you rank and render only the top few matches.

The same flow covers supported providers because the API returns one unified Contact object. You write the picker once instead of branching on the provider.

Send a GET request to /v3/grants/{grant_id}/contacts to read the user’s address book. The response is a data array of contact objects, each carrying an emails array plus name fields like given_name and surname. The default page size is 30 contacts and the maximum is 200, so you typically page through everyone once at load and cache the result.

The request below lists contacts for a grant. Raise limit to 200 to cut the number of round trips, then follow the next_cursor to fetch the next page.

Pass the next_cursor value as the page_token query parameter to read the next page. Keep looping until a response comes back without a next_cursor, which means you’ve reached the end of the address book.

The Nylas CLI pulls the contacts that power a recipient autocomplete: nylas contacts search filters by company, email, or phone, and --json output drops straight into an index or cache you build against, so you can prototype the picker from the terminal before writing any code.

# Search contacts to seed an autocomplete index
nylas contacts search --company "Acme" --has-email --json
# Include frequently emailed people, not just saved contacts
nylas contacts list --source inbox --json

Pull both the address_book and inbox sources to cover saved contacts and people the user sends email to often. Each query returns 50 contacts by default. See the contacts search and contacts list command reference.

How do I cache contacts for fast autocomplete?

Section titled “How do I cache contacts for fast autocomplete?”

Cache contacts client-side because per-keystroke API calls are too slow and too expensive. A network round trip adds 50 to 300 milliseconds per request, and a fast typist fires 5 or more keystrokes per second, so live calls both feel slow and burn through rate limits. Filtering an in-memory list instead returns matches in well under a millisecond.

Flatten the API response into one entry per email address, then filter that array by prefix. Wait about 150 milliseconds before processing the input so you match on a pause, not on every letter. The snippet below builds the index once and exposes a search function the input handler calls.

Choose a refresh interval that fits your product and provider limits. For grants that emit Contact notifications, the contact.updated and contact.deleted triggers can patch the cache between reconciliations. Native Yahoo grants don’t emit Contact notifications, so refresh them with paginated list requests. Native iCloud notifications are polled and best effort, so keep periodic reconciliation even when you subscribe.

How do I include people the user writes to but hasn’t saved?

Section titled “How do I include people the user writes to but hasn’t saved?”

Set the source query parameter to inbox to surface everyone the user has corresponded with, beyond saved contacts. The API recognizes 3 sources: address_book (contacts the user saved), domain (the organization directory), and inbox (contacts generated automatically from sent and received mail). The inbox source is what fills a picker with real correspondents who were never added by hand.

The request below gets inbox contacts for a separate merge with the saved address_book results. Query each source individually unless the specific grant type documents compound source support. Native iCloud and Yahoo grants reject compound source filters; their inbox source is also available only when separately enabled.

Coverage of these automatically generated contacts varies by provider. The inbox source needs the contacts.other.readonly scope on Google and People.Read on Microsoft, and Exchange (EWS) doesn’t support it. Native iCloud and Yahoo inbox contacts are separately gated and read-only. For unsupported grants, build the picker on saved contacts plus recipients you pull from the Messages API. The scopes reference lists the exact strings.

A good recipient picker is more than a prefix filter. A few details separate a usable index from a frustrating one, and most of them come down to how you shape the cached data before it ever reaches the dropdown.

Deduplicate by email, not by name. One person often appears more than once, as a saved address_book entry and again as an automatically generated inbox contact. Lowercase every address and key your index by email address so the same person shows up once. Two contacts can share a display name, so never deduplicate on name alone.

Rank by how often the user writes to someone. Alphabetical order buries the people the user writes to most. Pull recent sent messages from the Messages API, count how often each address appears as a recipient, and sort matches by that frequency. The 5 to 10 most-contacted addresses cover the majority of real sends, so weighting by send count makes the first suggestion correct far more often.

Don’t expose the whole address book. Return suggestions only after the user types at least 2 characters, and cap the dropdown at 5 to 8 entries. Dumping every contact into the page leaks the user’s full network into client-side state and slows rendering. Filter server-side if your address books run to thousands of entries.

Watch the provider quirks. Google organizes contacts into groups and polls for changes every five minutes. Microsoft Graph caps a single contact at three email addresses and can leave the email type as null. Native Yahoo allows at most one email address. Build your ranking on send frequency instead of provider labels.