Tutorial: Gmail to Exchange Online Migration¶
Status: Authored 2026-04-30 Audience: M365 administrators performing hands-on Gmail to Exchange Online migration using the Google Workspace migration feature in Exchange Admin Center. Duration: 2-4 hours for setup + migration time depending on mailbox sizes.
Prerequisites¶
Before starting this tutorial, confirm:
- Microsoft 365 tenant is provisioned with Exchange Online.
- Domain is verified in M365 (contoso.com).
- All target users are created in Entra ID with Exchange Online licenses assigned.
- You have Google Workspace super admin access.
- You have M365 Global Administrator or Exchange Administrator role.
Step 1: Create a Google Cloud project¶
1.1 Navigate to Google Cloud Console¶
Open console.cloud.google.com and sign in with your Google Workspace admin account.
1.2 Create a new project¶
- Click the project dropdown in the top navigation bar.
- Click New Project.
- Name the project:
M365-Migration. - Click Create.
- Select the new project from the dropdown.
1.3 Enable required APIs¶
Navigate to APIs & Services > Library and enable:
- Gmail API --- search "Gmail API" and click Enable.
- Google Calendar API --- search "Google Calendar API" and click Enable.
- Contacts API --- search "Contacts API" and click Enable.
- Google Workspace Admin SDK --- search "Admin SDK API" and click Enable.
Verification: Navigate to APIs & Services > Dashboard. All four APIs should show as "Enabled."
Step 2: Create a service account with domain-wide delegation¶
2.1 Create the service account¶
- Navigate to IAM & Admin > Service Accounts.
- Click Create Service Account.
- Name:
m365-migration. - Description:
Service account for M365 email migration. - Click Create and Continue.
- Skip role assignment (no GCP roles needed).
- Click Done.
2.2 Enable domain-wide delegation¶
- Click on the newly created service account.
- Click Advanced settings (or the Details tab).
- Under Domain-wide delegation, click Enable domain-wide delegation.
- Note the Client ID (a numeric string like
123456789012345678901).
2.3 Create and download a JSON key¶
- On the service account page, go to the Keys tab.
- Click Add Key > Create new key.
- Select JSON format.
- Click Create.
- Save the downloaded JSON file securely (e.g.,
m365-migration-key.json).
Security note
The JSON key file provides full access to user mailboxes. Store it securely and delete it after migration is complete. Never commit it to source control.
Step 3: Grant domain-wide delegation in Google Admin Console¶
3.1 Open Google Admin Console¶
Navigate to admin.google.com.
3.2 Configure API client access¶
- Navigate to Security > Access and data control > API controls.
- Click Manage Domain Wide Delegation (at the bottom of the page).
- Click Add new.
- Client ID: Paste the Client ID from Step 2.2.
- OAuth scopes: Enter the following scopes (comma-separated, no spaces after commas):
https://mail.google.com/,https://www.googleapis.com/auth/calendar,https://www.googleapis.com/auth/contacts,https://www.googleapis.com/auth/admin.directory.user.readonly,https://www.googleapis.com/auth/gmail.readonly
- Click Authorize.
Verification: The service account should appear in the domain-wide delegation list with the scopes listed.
Step 4: Configure the migration endpoint in Exchange Admin Center¶
4.1 Open Exchange Admin Center¶
Navigate to admin.exchange.microsoft.com or via the M365 Admin Center > Admin centers > Exchange.
4.2 Create migration endpoint¶
- Navigate to Migration in the left navigation.
- Click Migration endpoints tab.
- Click Add migration endpoint (+ icon).
- Select Google Workspace as the migration type.
- Enter a name:
Google Workspace Endpoint. - Email address: Enter a Google Workspace user email for connection testing (e.g., admin@contoso.com).
- Upload the JSON key file from Step 2.3.
- Click Next.
- The system tests the connection. Verify it shows Connected successfully.
- Click Save.
Alternative: Create endpoint via PowerShell¶
# Connect to Exchange Online
Connect-ExchangeOnline -UserPrincipalName admin@contoso.com
# Create the Google Workspace migration endpoint
$jsonContent = Get-Content "C:\migration\m365-migration-key.json" -Raw
New-MigrationEndpoint -Name "GoogleWorkspaceEndpoint" `
-Gmail `
-ServiceAccountKeyFileData ([System.Text.Encoding]::UTF8.GetBytes($jsonContent)) `
-EmailAddress "admin@contoso.com"
# Verify the endpoint
Get-MigrationEndpoint -Identity "GoogleWorkspaceEndpoint" |
Format-List Name, RemoteServer, ConnectionSettings
Step 5: Prepare the migration CSV file¶
5.1 Create the CSV file¶
Create a CSV file listing the email addresses to migrate. The email address must match both the Google Workspace email and the M365 UPN (or primary SMTP address).
Save as: C:\migration\batch1-it-department.csv
5.2 Validate user readiness¶
# Verify all users in the CSV have Exchange Online mailboxes
$csvUsers = Import-Csv "C:\migration\batch1-it-department.csv"
foreach ($user in $csvUsers) {
$mailbox = Get-Mailbox -Identity $user.EmailAddress -ErrorAction SilentlyContinue
if ($mailbox) {
Write-Host "READY: $($user.EmailAddress)" -ForegroundColor Green
} else {
Write-Host "NOT READY: $($user.EmailAddress) - No mailbox found" -ForegroundColor Red
}
}
Step 6: Create and start the migration batch¶
6.1 Via Exchange Admin Center¶
- Navigate to Migration in EAC.
- Click Add migration batch (+ icon).
- Select Migration to Exchange Online.
- Select Google Workspace migration.
- Batch name:
Batch1-IT-Department. - Select the migration endpoint:
Google Workspace Endpoint. - Upload the CSV file:
batch1-it-department.csv. - Configure target delivery domain:
contoso.mail.onmicrosoft.com. - Click Next.
- Configure start options:
- Start automatically: Yes (recommended).
- Complete automatically: No (recommended --- complete manually after validation).
- Click Save.
6.2 Via PowerShell¶
# Create the migration batch
New-MigrationBatch -Name "Batch1-IT-Department" `
-SourceEndpoint "GoogleWorkspaceEndpoint" `
-CSVData ([System.IO.File]::ReadAllBytes("C:\migration\batch1-it-department.csv")) `
-TargetDeliveryDomain "contoso.mail.onmicrosoft.com" `
-NotificationEmails "admin@contoso.com"
# Start the migration batch
Start-MigrationBatch -Identity "Batch1-IT-Department"
Step 7: Monitor migration progress¶
7.1 Exchange Admin Center dashboard¶
The Migration dashboard shows:
- Total mailboxes in the batch.
- Synced --- mailboxes that have completed initial sync.
- Syncing --- mailboxes currently syncing.
- Failed --- mailboxes with errors.
- Queued --- mailboxes waiting to start.
7.2 PowerShell monitoring¶
# Check batch status
Get-MigrationBatch -Identity "Batch1-IT-Department" |
Format-List Status, TotalCount, SyncedCount, FinalizedCount, FailedCount
# Check individual user status
Get-MigrationUser -BatchId "Batch1-IT-Department" |
Select-Object Identity, Status, ItemsSynced, ItemsSkipped, BytesSynced |
Format-Table -AutoSize
# Check for failed users
Get-MigrationUser -BatchId "Batch1-IT-Department" -Status Failed |
Select-Object Identity, Error |
Format-List
# Get detailed statistics for a specific user
Get-MigrationUserStatistics -Identity "user1@contoso.com" |
Format-List Status, EstimatedTotalTransferCount, TransferredItemCount,
BytesTransferred, PercentageComplete
7.3 Expected timelines¶
| Mailbox size | Estimated sync time | Notes |
|---|---|---|
| < 1 GB | 2-4 hours | Quick; most users |
| 1-5 GB | 4-12 hours | Average |
| 5-10 GB | 12-24 hours | Large mailbox |
| 10-50 GB | 1-3 days | Very large; may need throttle management |
| 50+ GB | 3-7 days | Executive mailboxes; contact Microsoft support for optimization |
Step 8: Validate migration¶
8.1 Spot-check migrated mailboxes¶
# Compare item counts
# Google Workspace: Check in Admin Console > Users > [user] > Account > Mailbox size
# Exchange Online:
Get-MailboxStatistics -Identity "user1@contoso.com" |
Select-Object ItemCount, TotalItemSize
8.2 Functional validation checklist¶
Log in to Outlook (web or desktop) as a migrated user and verify:
- Recent emails are present in the Inbox.
- Sent emails are in Sent Items.
- Gmail labels are mapped to folders or categories.
- Calendar events are present and correct (dates, times, attendees).
- Recurring events show the correct pattern.
- Contacts are present in People.
- Attachments on emails are accessible.
- Email search returns expected results.
8.3 User acceptance testing¶
Have 3-5 migrated users perform their daily email workflow:
- Send and receive emails (internal and external).
- Reply and forward emails.
- Search for historical emails.
- Check calendar events and schedule new meetings.
- Look up contacts.
- Access shared mailboxes (if configured).
Step 9: Complete the migration batch¶
After validation confirms the migration is successful:
9.1 Via Exchange Admin Center¶
- Navigate to Migration.
- Select the batch:
Batch1-IT-Department. - Click Complete migration batch.
- Confirm the action.
9.2 Via PowerShell¶
# Complete the migration batch
Complete-MigrationBatch -Identity "Batch1-IT-Department"
# Verify completion
Get-MigrationBatch -Identity "Batch1-IT-Department" |
Format-List Status, FinalizedCount
Completing the batch stops incremental sync
After completing a migration batch, incremental sync stops. New emails sent to Gmail will NOT sync to Exchange Online. Only complete the batch when you are ready for DNS cutover or when the coexistence period has ended for these users.
Step 10: Update DNS (MX records)¶
10.1 Pre-cutover: Reduce TTL¶
48 hours before MX cutover, reduce the MX record TTL to 300 seconds (5 minutes):
# At your DNS provider, change the MX record TTL
# From: 3600 (1 hour) or higher
# To: 300 (5 minutes)
10.2 Update MX records¶
Replace Google MX records with Microsoft 365 MX records at your DNS provider:
Remove:
| Priority | Record |
|---|---|
| 1 | ASPMX.L.GOOGLE.COM |
| 5 | ALT1.ASPMX.L.GOOGLE.COM |
| 5 | ALT2.ASPMX.L.GOOGLE.COM |
| 10 | ALT3.ASPMX.L.GOOGLE.COM |
| 10 | ALT4.ASPMX.L.GOOGLE.COM |
Add:
| Priority | Record |
|---|---|
| 0 | contoso-com.mail.protection.outlook.com |
10.3 Update SPF record¶
# Replace Google SPF with Microsoft SPF
# Old: v=spf1 include:_spf.google.com ~all
# New: v=spf1 include:spf.protection.outlook.com -all
10.4 Configure DKIM¶
# Enable DKIM signing in Exchange Online
New-DkimSigningConfig -DomainName "contoso.com" -Enabled $true
# Get CNAME records to add to DNS
Get-DkimSigningConfig -Identity "contoso.com" |
Format-List Selector1CNAME, Selector2CNAME
Add the CNAME records to your DNS:
| Record | Name | Value |
|---|---|---|
| CNAME | selector1._domainkey | selector1-contoso-com._domainkey.contoso.onmicrosoft.com |
| CNAME | selector2._domainkey | selector2-contoso-com._domainkey.contoso.onmicrosoft.com |
10.5 Configure DMARC¶
# Add DMARC TXT record
# Name: _dmarc
# Value: v=DMARC1; p=none; rua=mailto:dmarc-reports@contoso.com
# Start with p=none; move to p=quarantine then p=reject after validation
10.6 Verify DNS propagation¶
# Verify MX record
Resolve-DnsName -Name "contoso.com" -Type MX
# Verify SPF
Resolve-DnsName -Name "contoso.com" -Type TXT | Where-Object { $_.Strings -like "*spf*" }
# Verify DKIM
Resolve-DnsName -Name "selector1._domainkey.contoso.com" -Type CNAME
# Verify DMARC
Resolve-DnsName -Name "_dmarc.contoso.com" -Type TXT
Step 11: Post-migration tasks¶
11.1 Verify mail flow¶
Send test emails:
- Internal to internal (Outlook to Outlook).
- External to internal (Gmail/Yahoo to Outlook).
- Internal to external (Outlook to Gmail/Yahoo).
11.2 Configure Outlook clients¶
- Deploy Outlook desktop via Microsoft 365 Apps or Intune.
- Configure Outlook mobile via Intune MAM policies.
- Verify autodiscover works (profiles auto-configure).
11.3 Clean up¶
# Remove migration batch (after confirming success)
Remove-MigrationBatch -Identity "Batch1-IT-Department" -Confirm:$false
# Remove migration endpoint (after all batches complete)
Remove-MigrationEndpoint -Identity "GoogleWorkspaceEndpoint" -Confirm:$false
11.4 Delete the service account key¶
Delete the Google Cloud service account JSON key file after migration is complete. This key provides full access to user mailboxes and should not be retained.
Repeat for additional batches¶
For subsequent migration batches:
- Create a new CSV file for the next department.
- Create a new migration batch using the same endpoint.
- Start, monitor, validate, and complete.
- Repeat until all users are migrated.
Recommended batch order¶
| Batch | Department | Size | Notes |
|---|---|---|---|
| 1 | IT | 20-50 users | Pilot; highest technical capability |
| 2 | Executive assistants | 10-30 users | Validate delegation and calendar |
| 3 | Finance | 50-200 users | Test shared mailboxes and compliance |
| 4 | Engineering | 100-500 users | Largest batch; test throughput |
| 5 | Sales | 100-500 users | CRM integration validation |
| 6 | Remaining departments | Varies | Final batches |
Troubleshooting reference¶
| Symptom | Diagnostic | Resolution |
|---|---|---|
| "Authentication failed" on endpoint creation | Service account key invalid or expired | Re-download JSON key; verify domain-wide delegation |
| "Access denied" for specific mailboxes | OAuth scope missing | Add all required scopes to domain-wide delegation |
| Migration stuck at "Queued" | Migration service throttled | Wait; check service health at status.office365.com |
| Items skipped > 10% | Corrupted items or unsupported types | Export skipped item report; investigate individually |
| "Transient error" on items | Google API rate limiting | Migration will auto-retry; wait for completion |
| Mail flow not working after MX change | DNS propagation delay | Wait 2-4 hours; verify with nslookup/dig |
| SPF failures (external senders reject) | Old SPF record still cached | Wait for TTL expiration; verify SPF with MXToolbox |