# How to list IMAP contacts

Source: https://developer.nylas.com/docs/cookbook/contacts/list-contacts-imap/

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?

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

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](/docs/v3/getting-started/) with a valid API key
- An IMAP [connector](/docs/v3/auth/imap/) created with `provider` set to `imap`
- A [grant](/docs/v3/auth/) for the IMAP account, authorized with the user's username and password


> **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.


### IMAP authentication uses an app password

IMAP connectors don't support OAuth scopes, which the [scopes guide](/docs/dev-guide/scopes/) states directly. Instead you authenticate with the account's username and password. Most IMAP providers require an [application password](/docs/provider-guides/app-passwords/) 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

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.

```bash
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'

```

```json
{
  "request_id": "1",
  "data": [
    {
      "birthday": "1960-12-31",
      "company_name": "Nylas",
      "emails": [
        {
          "type": "work",
          "email": "leyah.miller@example.com"
        },
        {
          "type": "home",
          "email": "leyah@example.com"
        }
      ],
      "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"
}


```

```js [listContacts-Node.js SDK]

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();


```

```python [listContacts-Python SDK]

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](/docs/v3/email/contacts/).

## 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.

```bash
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>'
```

```js [filterImapContacts-Node.js SDK]
const contacts = await nylas.contacts.list({
  identifier: grantId,
  queryParams: {
    source: "address_book,inbox",
    email: "jane",
    limit: 10,
  },
});
```

```python [filterImapContacts-Python SDK]
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

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

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

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

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](/docs/provider-guides/app-passwords/) 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

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](/docs/v3/auth/imap/).

## 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.

```bash
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>'
```

```python [paginateImapContacts-Python SDK]
contacts = nylas.contacts.list(
    grant_id,
    query_params={"limit": 50, "page_token": next_cursor},
)
```

## What's next

- [How to list Google contacts](/docs/cookbook/contacts/list-contacts-google/) for the Google People API equivalent
- [How to list Microsoft contacts](/docs/cookbook/contacts/list-contacts-microsoft/) for the Graph API equivalent
- [How to list IMAP email messages](/docs/cookbook/email/messages/list-messages-imap/) to read mail from the same grant
- [IMAP provider guide](/docs/provider-guides/imap/) for connectors, app passwords, and credential handling
- [Manage contacts with the Contacts API](/docs/v3/email/contacts/) for create, update, delete, and the full schema