IMAP is a mail-sync protocol, not a contacts protocol. The IMAP RFC covers folders and messages, and says nothing about an address book, so there’s no standard GET /contacts to call. Nylas fills that gap: once an IMAP grant exists, the Contacts API derives contacts from the account and returns them through the same schema a Gmail or Outlook grant uses.
This recipe shows how to list contacts for an IMAP grant, filter them, and page through the results. You authenticate the account once with a username and password (often an app password), then read contacts with one call instead of writing your own participant-scraping logic on top of raw IMAP.
Why use Nylas instead of raw IMAP for contacts?
Section titled “Why use Nylas instead of raw IMAP for contacts?”Raw IMAP gives you mailboxes and messages, not an address book. To build a contact list yourself you’d connect over IMAP, walk folders, parse From, To, and Cc headers across thousands of messages, then remove duplicate addresses by hand. The Contacts API does that derivation and exposes the result through one GET /v3/grants/{grant_id}/contacts request.
- No contacts protocol to call. IMAP (RFC 3501) defines mailbox and message operations only, so contacts must be derived from message participants. The API handles that derivation.
- One schema across providers. The same request reads an IMAP, Gmail, or Exchange address book and returns identical fields, so your code never branches on provider.
- Credentials, not OAuth. IMAP connectors authenticate with a username and password, so there are no OAuth scopes or consent screens to configure for contact access.
- Managed connection handling. The API keeps the IMAP session and credential state for the grant, so you skip the connect, login, and reconnect loop.
Before you begin
Section titled “Before you begin”You need a connected IMAP account before any contacts come back. A grant represents one IMAP mailbox, and the contacts you list always belong to that single grant. IMAP grants authenticate with credentials rather than OAuth, so there’s no scope to request for contacts. Set up these 3 pieces first:
- A Nylas application with a valid API key
- An IMAP connector created with
providerset toimap - A grant for the IMAP account, authorized with the user’s username and password
IMAP authentication uses an app password
Section titled “IMAP authentication uses an app password”IMAP connectors don’t support OAuth scopes, which the scopes guide states directly. Instead you authenticate with the account’s username and password. Most IMAP providers require an application password for third-party tools rather than the normal login password, so redirect the user to generate one before authenticating. The grant expires the moment that password or app password changes, so re-authenticate the existing grant rather than creating a new one.
List IMAP contacts
Section titled “List IMAP contacts”Send a GET request to /v3/grants/{grant_id}/contacts with the grant ID for the IMAP account. The endpoint returns a data array of contact objects plus a request_id, and a single page returns up to 30 contacts by default (raise it to 200 with the limit parameter). Every object carries the same fields (emails, phone_numbers, job_title, company_name, and groups) that a Google or Outlook grant returns.
The samples below list contacts for one grant and print the unified response.
curl --compressed --request GET \ --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/contacts' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer <NYLAS_API_KEY>' \ --header 'Content-Type: application/json'{ "request_id": "1", "data": [ { "birthday": "1960-12-31", "company_name": "Nylas", "emails": [ { "type": "work", }, { "type": "home", } ], "given_name": "Leyah", "grant_id": "<NYLAS_GRANT_ID>", "groups": [{ "id": "starred" }, { "id": "friends" }], "id": "<CONTACT_ID>", "im_addresses": [ { "type": "jabber", "im_address": "jabber_at_leyah" }, { "type": "msn", "im_address": "leyah.miller" } ], "job_title": "Software Engineer", "manager_name": "Nyla", "middle_name": "Allison", "nickname": "Allie", "notes": "Loves ramen", "object": "contact", "office_location": "123 Main Street", "phone_numbers": [ { "type": "work", "number": "+1-555-555-5555" }, { "type": "home", "number": "+1-555-555-5556" } ], "physical_addresses": [ { "type": "work", "street_address": "123 Main Street", "postal_code": "94107", "state": "CA", "country": "US", "city": "San Francisco" }, { "type": "home", "street_address": "123 Main Street", "postal_code": "94107", "state": "CA", "country": "US", "city": "San Francisco" } ], "picture_url": "https://example.com/picture.jpg", "source": "address_book", "surname": "Miller", "web_pages": [ { "type": "work", "url": "<WEBPAGE_URL>" }, { "type": "home", "url": "<WEBPAGE_URL>" } ] } ], "next_cursor": "2"}import Nylas from "nylas";
const nylas = new Nylas({ apiKey: "<NYLAS_API_KEY>", apiUri: "<NYLAS_API_URI>",});
async function fetchContacts() { try { const identifier = "<NYLAS_GRANT_ID>"; const contacts = await nylas.contacts.list({ identifier, queryParams: {}, });
console.log("Recent Contacts:", contacts); } catch (error) { console.error("Error fetching drafts:", error); }}
fetchContacts();from nylas import Client
nylas = Client( "<NYLAS_API_KEY>", "<NYLAS_API_URI>")
grant_id = "<NYLAS_GRANT_ID>"
contacts = nylas.contacts.list( grant_id,)
print(contacts)For create, update, and delete operations plus the complete field list, see Manage contacts with the Contacts API.
Filter IMAP contacts
Section titled “Filter IMAP contacts”Three query parameters narrow an IMAP contact list: email, phone_number, and source. The source parameter chooses between saved entries (address_book) and the contacts the API derives from message participants (inbox). IMAP is one of only 2 providers, alongside iCloud, that accepts a compound source filter such as source=address_book,inbox in a single request. The group and recurse parameters apply to other providers, so leave them off for IMAP grants.
The email filter matches any contact whose address contains the value you pass, which makes it the right choice for an autocomplete box. The curl request below returns up to 10 IMAP contacts whose email contains jane from both saved and derived sources.
curl --request GET \ --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/contacts?source=address_book,inbox&email=jane&limit=10' \ --header 'Authorization: Bearer <NYLAS_API_KEY>'const contacts = await nylas.contacts.list({ identifier: grantId, queryParams: { source: "address_book,inbox", email: "jane", limit: 10, },});contacts = nylas.contacts.list( grant_id, query_params={ "source": "address_book,inbox", "email": "jane", "limit": 10, },)The phone_number filter is also supported for IMAP, so you can match a contact by a stored number when the address book carries one.
Things to know about IMAP contacts
Section titled “Things to know about IMAP contacts”IMAP carries no address book of its own, so contacts behave unlike any OAuth provider in 4 ways: where they come from, how the compound source filter works, the credential-based auth model, and how easily a grant breaks. Each one changes how you build, so it’s worth reading before you ship.
Contacts are derived from message participants
Section titled “Contacts are derived from message participants”IMAP has no address-book API, so the Contacts API builds the list from the people in an account’s messages. A saved-contact source like address_book reflects what the provider stores, while inbox surfaces senders and recipients the API extracts from From, To, and Cc headers. A mailbox with years of history can yield thousands of derived inbox entries against a much smaller saved set, so filter on source=address_book when you only want contacts the user explicitly saved.
IMAP supports compound source filters
Section titled “IMAP supports compound source filters”The source parameter accepts a single value (address_book, domain, or inbox) for most providers, but IMAP and iCloud are the only 2 that accept a comma-separated list in one request. Passing source=address_book,inbox returns saved and derived contacts together, which saves a second round trip when you want both. EWS, by contrast, rejects inbox entirely. Use the compound filter to populate a recipient picker that mixes real contacts with people the account has emailed before.
Authentication uses credentials, not OAuth scopes
Section titled “Authentication uses credentials, not OAuth scopes”IMAP connectors authenticate with a username and password, so there are no OAuth scopes gating contact access the way Google’s contacts.readonly or Microsoft’s Contacts.Read does. Most providers require an app password instead of the normal login password for third-party access. Because the grant holds only email-level access, an IMAP grant exposes email and contact data but never calendar data, even when the underlying service offers a calendar.
IMAP grants expire when the password changes
Section titled “IMAP grants expire when the password changes”IMAP grants are sensitive to credential changes: if the user changes their password or revokes the app password, the grant expires and contact calls start failing. Always re-authenticate the existing grant rather than deleting it and creating a new one, because IMAP object IDs are tied to the grant ID and change if the grant changes. Auth failures surface as codes like provider_not_responding and auth_limit_reached after 3 bad password attempts. For the full credential-failure list, see the IMAP authentication guide.
Paginate through IMAP contacts
Section titled “Paginate through IMAP contacts”Each list response returns up to 30 contacts by default (200 with limit) and, when more exist, a next_cursor value. Pass that value back as the page_token query parameter to fetch the following page, and repeat until the response omits next_cursor. This cursor pagination works the same for IMAP grants as for every other provider, so one loop drains an address book of any size.
curl --request GET \ --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/contacts?limit=50&page_token=<NEXT_CURSOR>' \ --header 'Authorization: Bearer <NYLAS_API_KEY>'contacts = nylas.contacts.list( grant_id, query_params={"limit": 50, "page_token": next_cursor},)What’s next
Section titled “What’s next”- How to list Google contacts for the Google People API equivalent
- How to list Microsoft contacts for the Graph API equivalent
- How to list IMAP email messages to read mail from the same grant
- IMAP provider guide for connectors, app passwords, and credential handling
- Manage contacts with the Contacts API for create, update, delete, and the full schema