O365 Migration: migrate Gmail to Exchange Online
Copy Gmail mail (labels as folders), contacts and calendars into Microsoft 365 mailboxes from a CSV of users – without sending invitations.
What you need
- Google side: a Google Workspace service account with domain-wide delegation (it can read every user). A Google sign-in works too, but only for the mailbox of the account that signed in.
- Microsoft side: the destination tenant on the Tenants page (Entra ID App ID) with
User.Read.All,Mail.ReadWrite,Contacts.ReadWriteandCalendars.ReadWrite. The destination mailboxes must exist (licensed for Exchange Online).
1. Allow Gmail, contacts and calendars for the service account
If you already use the service account for Google Drive, add three scopes to the same delegation entry:
- Google Cloud console → APIs & Services → Library → enable Gmail API, People API and Google Calendar API in the project of the service account.
- Google Admin console → Security → Access and data control → API controls → Manage domain-wide delegation → edit the client ID of the service account and set the scopes (comma-separated):
https://www.googleapis.com/auth/drive.readonly,https://www.googleapis.com/auth/gmail.readonly,https://www.googleapis.com/auth/contacts.readonly,https://www.googleapis.com/auth/calendar.readonly
New to service accounts? See Import from Google Drive for creating one.
2. The CSV
| Column | Meaning |
|---|---|
| SourceGmail | The Gmail / Google Workspace address |
| DestinationMailbox | The Microsoft 365 mailbox (user principal name or e-mail) |
SourceGmail,DestinationMailbox
jane.doe@contoso.com,jane.doe@fabrikam.com
john.smith@contoso.com,john.smith@fabrikam.com
Open Gmail in the left menu, pick the Google account and the destination tenant, click Import CSV (or add rows by hand; Fill destinations sets every destination to the same name at a new domain), then Check – it confirms the Gmail account and the Exchange mailbox for each row and explains anything missing.
What is migrated
| In Gmail | In Exchange Online / Outlook |
|---|---|
| Inbox, Sent, Drafts | Inbox, Sent Items, Drafts (drafts stay drafts) |
Your labels (Work/Clients → Work › Clients) | Folders – a message with two labels is in both folders. Or choose labels become categories: one copy in Inbox, Sent or Archive, labels as categories |
| Mail without a label (archived) | Archive |
| Unread, starred | Unread, flagged |
| Attachments, inline images | Attachments (large ones in parts), inline images keep working |
| Spam and Trash | Skipped by default (option) |
| Contacts ("My contacts") | Contacts – names, up to 3 e-mail addresses, phones, company, addresses, birthday, notes |
| Calendars you own | Calendars – the primary one into the default calendar, others by name |
| Events and recurring series | Events created without attendees, so nobody receives an invitation; organizer and guests are noted in the event |
- Repeat rules Outlook can't express (for example "first Monday or Tuesday") are imported as the first occurrence, with a warning in the report. Single changed occurrences of a series keep the series' time.
- Calendars you only subscribe to (holidays, other people's) are not copied.
- Only items since limits mail and events to a date.
Run it again
Every imported item carries its Gmail ID, so running again only adds what is new – messages are not even downloaded twice. A common plan: migrate everyone, switch the MX records, then run once more to pick up the last messages.
Common messages
| Message | Fix |
|---|---|
| Domain-wide delegation … a scope is missing | Add the Gmail, Contacts and Calendar scopes above to the delegation entry; wait a few minutes |
| The Gmail API is not enabled | Enable it (and the People and Calendar APIs) in the service account's Cloud project |
| … is signed in as …, so it can only migrate that mailbox | Use a Workspace service account for other users |
| This Google sign-in does not allow Gmail API access | The account was signed in for Google Drive only – Google Drive → the account → Sign in again |
| … has no Exchange Online mailbox | License the user for Exchange Online, then run again |
Updated 2026-10-23
