# Migrate from Gmail API and Microsoft Graph

Source: https://developer.nylas.com/docs/cookbook/use-cases/build/migrate-from-gmail-graph/

Teams that support both Google and Microsoft accounts usually end up maintaining two integrations that do the same thing. The Gmail API uses labels, hex message IDs, and a GCP OAuth project. Microsoft Graph uses folders, long base64 IDs, and an Azure app registration. Reading a message means one code path for Google and a separate one for Microsoft, and calendar adds a third and fourth. A unified API collapses those parallel stacks into a single schema and a single auth flow.

This guide covers why teams consolidate, how Gmail API and Graph concepts map to the unified equivalents, the steps to migrate without breaking what already works, and the provider quirks the unified layer absorbs for you.

## Why consolidate the Gmail API and Microsoft Graph?

Running both provider APIs means two schemas, two OAuth apps, and two sets of quirks for every feature. A unified API gives you 1 schema and 1 auth flow across 6 providers, so a single code path reads, sends, and schedules for Google and Microsoft accounts alike. You build a feature once instead of twice.

The duplication is structural, not cosmetic. The Gmail API and Microsoft Graph model the same mailbox differently: labels versus folders, short hex IDs versus long base64 IDs, `users.messages.list` versus `GET /me/messages`. Each one wants its own consent screen, its own token store, and its own retry logic for its own rate limits. When a third provider like Yahoo or an IMAP host enters scope, you write a third integration from scratch. A unified API normalizes the data model so 1 `messages` object covers every provider, and the same grant exposes calendar and contacts. Most teams find that roughly 80% of their provider-specific branching disappears once the schema is shared, which is the real payoff of consolidation.

## How do Gmail API and Graph concepts map to a unified schema?

Most concepts have a direct equivalent. A Gmail label and a Graph mail folder both become an entry in a unified `folders` array. The Gmail API's `users.messages.list` and Graph's `GET /me/messages` both become 1 call: `GET /v3/grants/{grant_id}/messages`. The table below pairs the common concepts across both provider APIs.

The mapping is not identical everywhere, and that gap is exactly what the unified layer absorbs. Gmail's labels are many-to-one per message while Graph folders are one-to-one, so the unified `folders` array accepts both shapes without branching across the 2 providers. Across the 3 core objects (messages, events, contacts), a single grant replaces the two separate OAuth apps you would otherwise wire up by hand.

| Gmail API / Microsoft Graph | Unified equivalent | Notes |
|---|---|---|
| `users.messages.list` / `GET /me/messages` | `GET /v3/grants/{grant_id}/messages` | One call for both providers |
| `users.messages.send` / `POST /me/sendMail` | `POST /v3/grants/{grant_id}/messages/send` | Sends from the user's mailbox |
| Gmail labels / Graph mail folders | Unified `folders` array | Labels and folders both normalize here |
| `events.list` / `GET /me/events` | `GET /v3/grants/{grant_id}/events?calendar_id=<CALENDAR_ID>` | One calendar schema; `calendar_id` is required |
| `people.connections.list` / `GET /me/contacts` | `GET /v3/grants/{grant_id}/contacts` | Same contact model |
| GCP OAuth project / Azure app registration | One Nylas connector per provider | Configured once in the dashboard |
| Per-provider access token | One grant per connected account | Token refresh handled for you |

## What are the steps to migrate off the provider APIs?

Migrate in 4 stages: set up connectors, connect accounts to create grants, swap read and send calls to the grant endpoints, then move calendar and contacts. Run the old provider APIs alongside the new path and shift traffic gradually so no production feature depends on an untested route.

Start by configuring 1 connector per provider in the dashboard, which replaces your GCP OAuth project and Azure app registration as the place auth lives. See [getting started](/docs/v3/getting-started/) to create a project and connectors. Next, connect user accounts so each one produces a grant, the single credential that stands in for a per-provider access token. Then point your read and send calls at the grant endpoints. Listing messages becomes `GET /v3/grants/{grant_id}/messages` regardless of whether the account is Google or Microsoft, and the [list Google messages](/docs/cookbook/email/messages/list-messages-google/) guide shows the exact request and response shape. Keep the old Gmail API and Graph calls live during this phase and route a small slice of users (start with 10%) through the grant path while you compare results. Once messages are stable, move calendar to `GET /v3/grants/{grant_id}/events?calendar_id=<CALENDAR_ID>` (the `calendar_id` query parameter is required) and contacts to the matching grant endpoint, since both ride the same grant you already created.

## What gotchas does the unified layer absorb?

The unified layer hides 3 provider quirks: Gmail many-label messages versus Graph single-folder ones, differing message ID formats, and separate rate-limit models. You still plan for per-user send limits and OAuth consent, since those live with the provider, not the abstraction.

Gmail messages carry multiple labels at once while Graph messages sit in one folder, and the unified `folders` array represents both without a code branch. Message IDs differ too: Gmail uses short hex strings around 16 characters, Graph uses long base64 strings, and both are stable and safe to store. The unified ID stays consistent across the API. Rate limits are the honest exception. Google enforces quotas per-user and per-project, Microsoft throttles per-mailbox, and the API retries on your behalf, but aggressive polling for many users can still exhaust a provider quota. Use [webhooks](/docs/v3/notifications/) instead of polling to avoid that. Send limits also stay provider-bound: Gmail consumer accounts sit near 500 recipients per day, so grant sends suit per-user mail rather than bulk campaigns. If you only ever support one provider and want full control, the native API still fits. The unified path earns its place the moment you support both Google and Microsoft, or add a third provider. For send-only stacks, see [migrate from a CPaaS](/docs/cookbook/use-cases/build/migrate-from-cpaas/) instead.

## What's next

- [List Google email messages](/docs/cookbook/email/messages/list-messages-google/) for the unified read call on Google accounts
- [Migrate from a CPaaS email stack](/docs/cookbook/use-cases/build/migrate-from-cpaas/) if you are moving off a send-only provider instead
- [Getting started with Nylas](/docs/v3/getting-started/) to create a project, connectors, and your first grant