Skip to content
Skip to main content

How to list Microsoft email messages

Last updated:

If you’re building an app that reads email from Microsoft 365 or Outlook accounts, you have two choices: work directly with the Microsoft Graph API, or use Nylas as a unified layer that handles the provider differences for you.

With Nylas, the API call to list messages is the same whether the account is Microsoft, Google, or IMAP. The differences show up in folder naming, message ID formats, admin consent requirements, and rate limiting. This guide covers all of that.

How do I list Microsoft email messages with the Nylas API?

Section titled “How do I list Microsoft email messages with the Nylas API?”

Send a GET request to /v3/grants/{grant_id}/messages with your API key. The endpoint returns the 50 most recent Outlook or Microsoft 365 messages by default and up to 200 per page, with base64-encoded message IDs and internal folder names like sentitems normalized into one schema. The same call works across Gmail, Yahoo, and IMAP. See List messages for the request and response.

Why use Nylas instead of Microsoft Graph directly?

Section titled “Why use Nylas instead of Microsoft Graph directly?”

The Microsoft Graph API is capable, but integrating it requires significant setup. You need to register an app in Azure AD, configure OAuth scopes, manage token refresh with MSAL, handle admin consent flows for enterprise tenants, and deal with Microsoft-specific data formats like base64-encoded message IDs and internal folder names like sentitems.

Nylas handles all of that behind a single REST API. Your code stays the same whether you’re reading from Outlook, Gmail, or Yahoo. No Azure AD registration, no MSAL token lifecycle, no mapping deleteditems to “Trash” in your UI. If you need to support multiple providers or want to skip the Graph onboarding, Nylas is the faster path.

If you only need Microsoft and already have Graph experience, you can integrate directly.

You’ll need:

  • A Nylas application with a valid API key
  • A grant for a Microsoft 365 or Outlook account
  • The Mail.Read scope enabled in your Azure AD app registration

Microsoft organizations often require admin approval before third-party apps can access mailbox data. If your users see a “Need admin approval” screen during auth, it means their organization restricts user consent.

You have two options:

  • Ask the tenant admin to grant consent for your app via the Azure portal
  • Configure your Azure app to request only permissions that don’t need admin consent

Nylas has a detailed walkthrough: Configuring Microsoft admin approval. If you’re targeting enterprise customers, you’ll almost certainly need to deal with this.

You also need to be a verified publisher. Microsoft requires it since November 2020, and without it users see an error during auth.

Make a List Messages request with the grant ID. Nylas returns the 50 most recent messages by default. These examples limit results to 5:

Admin consent and Azure AD registration are the usual friction points on Microsoft 365, so proving a grant syncs is the first thing worth doing. The Nylas CLI does it from your terminal: nylas email list returns the account’s 10 most recent inbox messages through the Messages API, with no integration code required.

The Nylas CLI mirrors the Messages API, so you can read the same inbox from your terminal without writing any code. After nylas init and nylas auth login, the email list command returns the 10 most recent inbox messages by default and pages through everything automatically once --limit goes over 200:

# List the 10 most recent inbox messages
nylas email list
# Show only unread messages from a specific sender
nylas email list --unread --from [email protected]
# Fetch everything across all folders, paginated automatically
nylas email list --all --all-folders --max 500

To find specific messages rather than list them, email search runs a full-text query with its own filters for sender (--from), date range (--after and --before), and attachments (--has-attachment). Search returns 20 results by default and only fetches more than one page once --limit goes over 200:

# Full-text search restricted to one sender, attachments only
nylas email search "invoice" --from [email protected] --has-attachment

Both commands accept --json, so you can pipe results into jq or a script. See the email list and email search command reference for every flag.

Microsoft sorts mail into folders rather than labels, and Nylas normalizes the internal names like inbox and sentitems into the folders array on each message. To filter by folder, run nylas email folders list first and pass the folder ID it returns, since enterprise tenants often rename or add folders. Each page of results holds up to 200 messages. To send Outlook mail from the same command line, see Send email from the terminal.

You can narrow results with query parameters. Here’s what works with Microsoft accounts:

ParameterWhat it doesExample
subjectMatch on subject line?subject=Weekly standup
fromFilter by sender[email protected]
toFilter by recipient[email protected]
unreadUnread only?unread=true
inFilter by folder or label ID?in=INBOX
received_afterAfter a Unix timestamp?received_after=1706000000
received_beforeBefore a Unix timestamp?received_before=1706100000
has_attachmentOnly results with attachments?has_attachment=true

Combining filters works the way you’d expect. This pulls unread messages from a specific sender:

Microsoft supports the search_query_native parameter, which maps to the $search query parameter in Microsoft Graph. This uses Microsoft’s Keyword Query Language (KQL) syntax.

Like Google, Microsoft restricts which query parameters you can combine with search_query_native. You can only use it with in, limit, and page_token. Other query parameters will return an error.

See the search best practices guide for more on search_query_native across providers.

A few provider-specific details that matter when you’re building against Microsoft accounts.

Microsoft uses internal names like sentitems, deleteditems, and junkemail instead of the display names you see in the Outlook UI. Here’s the mapping:

Outlook UI nameMicrosoft internal name
Inboxinbox
Sent Itemssentitems
Draftsdrafts
Deleted Itemsdeleteditems
Junk Emailjunkemail
Archivearchive

If you’re building a folder picker or filtering messages by folder, call the List Folders endpoint first to get the actual folder IDs and display names for the account. Don’t hardcode folder names because some organizations customize them.

Microsoft message IDs look like AAMkAGI2TG93AAA=, which are long base64 strings compared to Google’s shorter numeric IDs. These IDs are stable and persist across syncs, so you can safely store and reference them. Just be aware that they’ll take more space in your database and URLs.

New messages typically appear within a few seconds of being sent or received. If a message you know exists isn’t showing up in list results yet, wait a moment and retry. This is a Microsoft-side delay, not a Nylas one.

For apps that need real-time notification of new messages, don’t poll. Use webhooks instead. Nylas will push a notification to your server as soon as the message syncs.

Microsoft throttles API requests at the mailbox level. Its documented ceiling for the Outlook service is 10,000 requests per 10-minute window per app per mailbox, plus 4 concurrent requests. If your app hits a 429 response, Nylas honors the Retry-After header and retries automatically, so you don’t need to implement backoff logic yourself. See Microsoft Graph throttling limits for the full table.

That said, if you’re building something that checks a mailbox frequently (like every few seconds), you’ll burn through rate limits fast. Webhooks solve this by notifying you of changes in real time without any polling requests.

Microsoft handles attachments differently from Google. A few things to watch for:

  • Inline images in HTML email bodies are returned as attachments with is_inline: true. If you’re rendering email content, you’ll need to replace cid: references in the HTML with the actual attachment URLs.
  • Attachment size limits vary. Microsoft allows up to 150 MB for messages with attachments, but individual files over 3 MB should use the upload attachment flow.
  • Calendar invites (.ics files) show up as attachments on messages. Check the content_type field for text/calendar or application/ics.

Microsoft 365 sorts incoming mail into Focused and Other using its own relevance model, but both sit in the same inbox folder. A List Messages call returns messages from both, and the API doesn’t split them into separate folders. Microsoft Graph exposes the split through the inferenceClassification property (focused or other) if you need to replicate it. Microsoft introduced Focused Inbox in 2016, and many enterprise tenants leave it enabled, so don’t assume inbox means “Focused only”.

Reading a shared or delegated mailbox needs a grant authorized for that mailbox plus the right Microsoft permission: the signed-in user needs Full Access to the shared mailbox, and your Azure app needs delegated mail scopes. Shared mailboxes under 50 GB don’t require their own Microsoft 365 license, which is why support and sales aliases often use them. See Microsoft’s shared mailbox overview for the access model.

The Messages API returns paginated responses. When there are more results, the response includes a next_cursor value. Pass it back as page_token to get the next page:

Keep paginating until the response comes back without a next_cursor.