HomeServicesManaged IT ServicesAI DeploymentInsightsAnswersAboutFree Consultation
Tenant-to-tenant & M&A

How do I set up Microsoft's native cross-tenant mailbox migration in Exchange Online, step by step?

Short answer

You run it from the target tenant. Buy a Cross Tenant User Data Migration license for each user, register a multi-tenant Entra app with the Mailbox.Migration permission, and have the source admin consent to it. Create an organization relationship in both tenants, scoped by a mail-enabled security group in the source. Stamp target MailUsers with the source ExchangeGuid, ArchiveGuid and X500 addresses, then create a migration batch and complete it.

Key facts

  • Every migrated user needs a one-time Cross Tenant User Data Migration license, assigned on the source or target user; Microsoft offers no exceptions.
  • The target tenant is configured first, and the migration batch is created in the target tenant.
  • The source tenant scopes which mailboxes can leave with a mail-enabled security group set as MailboxMovePublishedScopes.
  • Mailboxes on any type of hold are not migrated, and the move for them is blocked.
  • Microsoft recommends no more than 2,000 mailboxes per batch and submitting batches about two weeks before cutover.
  • Microsoft 365 Groups, mailbox signatures and Outbox items do not migrate, and cross-cloud moves (for example Worldwide to Government) are not supported.

Prerequisites and licensing

Cross-tenant mailbox migration uses the Mailbox Replication Service (MRS) and the New-MigrationBatch cmdlet. It works for cloud-only tenants, hybrid tenants, or a mix. The two tenants must use different domain names, and both must be in the same Microsoft cloud.

Licensing is the step people skip. Each user needs a Cross Tenant User Data Migration add-on license (a one-time, per-user fee). You can assign it on the source or the target user, and it also covers OneDrive cross-tenant migration. Without it the move fails with CrossTenantMigrationWithoutLicensePermanentException. Users in both tenants also need an Exchange Online license.

  • Organization Management (organization administrator) in Exchange Online in each tenant for the one-time setup. Only this role can change -MailboxMoveCapability on an organization relationship.
  • Move Mailboxes role in the target tenant for whoever creates and runs the batches.
  • Rights in the Microsoft Entra admin center to register an app and grant admin consent in each tenant.
  • The other tenant's tenant ID (a GUID, not a domain name). Find it in Microsoft Entra admin center > Overview > Tenant ID.
  • The ExchangeOnlineManagement module: Install-Module ExchangeOnlineManagement, then Connect-ExchangeOnline in each tenant.
  • At least one mail-enabled security group in the source tenant. Over 10,000 users, Microsoft recommends several groups. Nested groups work but are not recommended.

Step 1: Create the migration app in the target tenant

Do the target tenant first. Separate admins can handle each tenant; nobody needs credentials for both.

  1. Sign in to the Microsoft Entra admin center (entra.microsoft.com) as a target tenant admin.
  2. Go to Microsoft Entra ID > App registrations > New registration.
  3. Under Supported account types, choose Accounts in any organizational directory (Any Microsoft Entra directory - Multi-tenant). Under Redirect URI, select Web and enter https://office.com. Select Register.
  4. Open the new app and copy the Application (client) ID from Essentials.
  5. Select API permissions. Remove the default User.Read if you want (it is not needed).
  6. Select Add a permission > APIs my organization uses, search for Office 365 Exchange Online, choose Application permissions, expand Mailbox, select Mailbox.Migration, then Add permissions.
  7. Select Certificates & secrets > Client secrets > New client secret. Set a description and expiry, then copy the secret value now. It is shown only once.
  8. Go to Enterprise applications, open the app, select API Permissions, then Grant admin consent for [your tenant] and Accept.
  9. Send the source admin this consent URL, with their onmicrosoft.com name and your app ID filled in: https://login.microsoftonline.com/contoso.onmicrosoft.com/adminconsent?client_id=[application_id]&redirect_uri=https://office.com

Step 2: Source tenant consent, scope group and organization relationship

  1. The source admin opens the consent URL and selects Accept. The app then appears under Enterprise applications in the source tenant.
  2. The source admin connects to Exchange Online PowerShell and runs the script below. It creates the mail-enabled security group if needed and an organization relationship with -MailboxMoveCapability RemoteOutbound.
  3. Add every mailbox that is allowed to move to that group. Anything outside the group fails with MailboxNotInCrossTenantMigrationScopeException.
# Source tenant: scope group and RemoteOutbound organization relationship (Microsoft's documented script)
# SOURCE tenant: scope group + organization relationship that allows outbound moves
Connect-ExchangeOnline -UserPrincipalName [email protected]

$targetTenantId = "[target tenant ID GUID]"
$appId = "[application ID of the migration app you consented to]"
$scope = "[mail-enabled security group of users allowed to migrate]"
$orgrelname = "[name of your new organization relationship]"

$dehydrated = Get-OrganizationConfig | select isdehydrated
if ($dehydrated.isdehydrated -eq $true) { Enable-OrganizationCustomization }
if (!(New-DistributionGroup -Type Security -Name $scope)) { Write-Host "Group already exists." }

$orgrels = Get-OrganizationRelationship
$existingOrgRel = $orgrels | ?{$_.DomainNames -like $targetTenantId}
if ($null -ne $existingOrgRel)
{
    Set-OrganizationRelationship $existingOrgRel.Name -Enabled:$true -MailboxMoveEnabled:$true -MailboxMoveCapability RemoteOutbound -OAuthApplicationId $appId -MailboxMovePublishedScopes $scope
}
if ($null -eq $existingOrgRel)
{
    New-OrganizationRelationship $orgrelname -Enabled:$true -MailboxMoveEnabled:$true -MailboxMoveCapability RemoteOutbound -DomainNames $targetTenantId -OAuthApplicationId $appId -MailboxMovePublishedScopes $scope
}

# Add each in-scope mailbox to the group
Add-DistributionGroupMember -Identity $scope -Member [email protected]

Step 3: Migration endpoint and organization relationship in the target tenant

Wait until the source admin has consented. If not, New-MigrationEndpoint fails with an authentication error.

# Target tenant: create the cross-tenant migration endpoint
# Run in the TARGET tenant after the source admin has consented to the app
Install-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName [email protected]

$AppId = "[Application (client) ID of the migration app]"
$name = "[name of your new migration endpoint]"
$remote = "contoso.onmicrosoft.com"   # source tenant onmicrosoft.com name
$secret = "[client secret value saved earlier]"

# Enable customization if tenant is dehydrated
$dehydrated = Get-OrganizationConfig | select isdehydrated
if ($dehydrated.isdehydrated -eq $true) {Enable-OrganizationCustomization}

$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $AppId, (ConvertTo-SecureString -String $secret -AsPlainText -Force)
New-MigrationEndpoint -RemoteServer outlook.office.com -RemoteTenant $remote -Credentials $Credential -ExchangeRemoteMove:$true -Name $name -ApplicationId $AppId

# Target tenant: Inbound organization relationship
# TARGET tenant: organization relationship that allows inbound moves
$sourceTenantId = "[source tenant ID GUID]"
$orgrelname = "[name of your new organization relationship]"
$orgrels = Get-OrganizationRelationship
$existingOrgRel = $orgrels | ?{$_.DomainNames -like $sourceTenantId}
If ($null -ne $existingOrgRel)
{
    Set-OrganizationRelationship $existingOrgRel.Name -Enabled:$true -MailboxMoveEnabled:$true -MailboxMoveCapability Inbound
}
If ($null -eq $existingOrgRel)
{
    New-OrganizationRelationship $orgrelname -Enabled:$true -MailboxMoveEnabled:$true -MailboxMoveCapability Inbound -DomainNames $sourceTenantId
}

Step 4: Prepare target MailUsers

Each user must already exist in the target tenant as a MailUser with attributes copied from the source mailbox. The move will not start without them.

Do not assign the target Exchange Online license before ExchangeGuid is stamped. If you do, Exchange creates a new empty mailbox and the move fails. Microsoft suggests licensing after the move, inside the 30-day grace period. If the target object once had a mailbox, Set-User <identity> -PermanentlyClearPreviousMailboxInfo clears it. That is permanent, so check first.

  • ExchangeGuid: must match the source mailbox.
  • ArchiveGuid: must match, if the source has an archive.
  • X500 proxies: add x500:<source LegacyExchangeDN> plus every X500 address already on the source mailbox. This also keeps replies to old mail working.
  • UserPrincipalName and PrimarySmtpAddress: the user's new identity in the target tenant.
  • ExternalEmailAddress: the user's current source mailbox address (for example [email protected]). Set PrimarySmtpAddress too, or this value becomes the primary address and the move fails.
  • Only SMTP proxies for domains the target tenant owns. A foreign domain causes NotAcceptedDomainException or blocks the MailUser to mailbox conversion.
  • If you sync from on-premises with Microsoft Entra Connect, stamp these on the on-premises object and let it sync.

Source tenant: export the needed attributes

# SOURCE tenant: export the attributes the target MailUser needs
Get-Mailbox [email protected] |
  Select-Object PrimarySMTPAddress,Alias,DisplayName,ExchangeGuid,ArchiveGuid,LegacyExchangeDn,EmailAddresses |
  Export-Clixml "$home\desktop\UsersToMigrate.xml"

# Target tenant: stamp GUIDs and X500 addresses on the MailUser
# TARGET tenant (cloud-only): stamp an existing MailUser
# ExternalEmailAddress = the user's mailbox address in the SOURCE tenant
$m = Import-Clixml "$home\desktop\UsersToMigrate.xml"
$x500 = "x500:" + $m.LegacyExchangeDn

Set-MailUser [email protected] -ExchangeGuid $m.ExchangeGuid -ArchiveGuid $m.ArchiveGuid -EmailAddresses @{add = $x500}

# Copy every existing X500 proxy from the source mailbox too
$m.EmailAddresses | Where-Object { $_ -match "x500" } | ForEach-Object {
  Set-MailUser [email protected] -EmailAddresses @{add = "$_"}
}

# Check for an old cloud mailbox on the target object
Get-User [email protected] | select Name, *recipient* | Format-Table -AutoSize

Step 5: Create, sync and complete the migration batch

Batches run from the target tenant. The CSV must list the target tenant addresses, not the source ones. -TargetDeliveryDomain tells MRS which target proxy to write as the forwarding address on the source object after the move. Keep each batch at or under 2,000 mailboxes and move delegates with the people they work for, since cross-tenant mailbox and calendar permissions are not supported.

In the portal: Exchange admin center > Migration > Add migration batch, then choose the cross-tenant migration option and the endpoint you created. When the batch shows Synced, select it and choose Complete migration batch.

# Target tenant: test, create and complete the batch
# TARGET tenant: test the endpoint against one prepared MailUser
Test-MigrationServerAvailability -EndPoint "[migration endpoint name]" -TestMailbox "[email protected]"

# users.csv uses TARGET tenant addresses
# EmailAddress
# [email protected]

New-MigrationBatch -Name T2Tbatch -SourceEndpoint "[migration endpoint name]" -CSVData ([System.IO.File]::ReadAllBytes('C:\Migration\users.csv')) -Autostart -TargetDeliveryDomain northwindtraders.onmicrosoft.com

# When the batch shows Synced, finalize it
Complete-MigrationBatch -Identity T2Tbatch

What does not migrate, and what changes for users

Only user-visible mailbox content moves: email, contacts, calendar, tasks, notes and the Recoverable Items folders. After completion the source mailbox is deleted and becomes a MailUser that forwards to the target, so the source tenant can no longer search it with eDiscovery.

  • Not migrated: Microsoft 365 Groups, Teams chat folder content, Outbox items, mailbox signatures and sensitivity labels.
  • Teams meetings move, but their join links break. Users must recreate them.
  • Send on Behalf (GrantSendOnBehalfTo) does not move. Re-add it with Set-Mailbox after the move.
  • Users rebuild their Outlook profile with the new UPN and address, then resync the OST.
  • Archives move, including up to 12 auxiliary archives.
  • Afterward, remove the endpoint and organization relationships with Remove-MigrationEndpoint and Remove-OrganizationRelationship.

Common errors and fixes

ErrorCauseFix
CrossTenantMigrationWithoutLicensePermanentExceptionNo Cross Tenant User Data Migration license on the source or target user.Assign the license, then resume the batch.
MailboxNotInCrossTenantMigrationScopeExceptionUser not in the source scope group, or MailboxMovePublishedScopes not set.Add the user to the group, check the source organization relationship, resume the batch.
MissingExchangeGuidExceptionTarget MailUser lacks the correct ExchangeGuid.Set-MailUser <id> -ExchangeGuid <source GUID>, then resume.
NotAcceptedDomainExceptionTarget MailUser has a proxy address for a domain the target tenant does not own.Set-MailUser <id> -EmailAddress @{remove="smtp:..."}, then resume.
UserDuplicateInOtherBatchExceptionUser is already in another batch.Get-MigrationUser -Identity <id> -IncludeAssociatedUsers | Remove-MigrationUser, then add to one batch.
SourceMailboxAlreadyBeingMovedPermanentExceptionAn existing move request (possibly an internal Microsoft move).Remove the user, wait for or remove the other move, then re-add.
UserAlreadyHasDemotedArchiveExceptionUser previously had a disabled archive.Remove the disabled archive (irreversible) or re-enable it and update ArchiveGuid on the target.
MailboxExceedsTargetQuotaPermanentException (and related quota errors)Source mailbox or archive is larger than the target quota.Enable archive or auto-expanding archive in the source to shrink the primary mailbox, then retry.

How to verify it worked

  1. Before the batch, run Test-MigrationServerAvailability against the endpoint with one prepared MailUser. Microsoft also publishes a validation script at aka.ms/crosstenantmailboxmigrationvalidationscript.
  2. In Exchange admin center > Migration, select the batch, then under Migration details select View details to see each user's status, items synced and items skipped.
  3. Select a user and choose Download the report for this user for a detailed report.
  4. After completion, confirm the target object is now a mailbox and the source object is a MailUser whose ExternalEmailAddress points at the target delivery domain.
# Check batch, user and move status
# TARGET tenant
Get-MigrationBatch -Identity T2Tbatch
Get-MigrationUser -BatchId T2Tbatch
Get-MigrationUser -EmailAddress [email protected] | Get-MigrationUserStatistics

# Only cross-tenant moves, then per-user detail and report
Get-MoveRequest -Flags "CrossTenant"
Get-MoveRequestStatistics -Identity [email protected]
Get-MoveRequestStatistics -Identity [email protected] -IncludeReport | Export-CSV C:\Migration\MRStats.csv

# SOURCE tenant: the old mailbox should now be a MailUser pointing at the target
Get-MailUser [email protected] | select ExternalEmailAddress, EmailAddresses

When to call a consultant

Tell us about both tenants and your timeline. We will tell you plainly whether native migration fits and what a pilot would look like.

Take the 2-min fit check Talk to a specialist

How Accred Consulting approaches it

We start with a free call to understand both tenants, the user count and the deadline. Then you get a written plan covering licensing, the app and organization relationship setup, how target MailUsers will be built and synced, batch groupings that keep delegates together, and the Outlook profile steps users will need. We run a pilot batch with a few real mailboxes before any bulk moves and fix attribute problems there. Our US-based team scopes the work as fixed-fee or hourly, and we coordinate with the other company's admins when they own the source tenant.

Track record: 475+ client projects, 2,000+ migration workstreams and 210,000+ users migrated by a US-based team. Company facts · Case studies

Related questions

The target tenant. The target admin creates the Entra app, the migration endpoint and the batch. The source admin only consents to the app, creates the scope group and sets up the RemoteOutbound organization relationship. Neither admin needs credentials for the other tenant, which helps when two separate companies are involved.
Yes. Microsoft requires one per migrated user, as a one-time fee, assigned on either the source or target user. It also covers OneDrive cross-tenant migration. Microsoft states it offers no exceptions, and moves fail with CrossTenantMigrationWithoutLicensePermanentException when the license is missing. Buy, or confirm you can buy, the licenses before you start setup.
Not at the same time. A domain can belong to only one tenant, so the source and target must use different domains during migration. Many teams move the domain at cutover, after the mailboxes. Until then, the source MailUser forwards mail to the target tenant, much like Exchange hybrid mail flow.
Yes, but it needs setup in reverse. Do not run the organization relationship scripts again. Instead update the existing relationships so both tenants have Inbound and RemoteOutbound capability, point the new source's OAuthApplicationId to an app created in the new target, and set a new scope group. Then create a batch from the original tenant.
Most often an Exchange Online license was assigned to the target MailUser before ExchangeGuid was stamped, so Exchange provisioned a new mailbox. Clear it with Set-User -PermanentlyClearPreviousMailboxInfo (this cannot be undone), stamp the correct ExchangeGuid, and retry. To avoid it, license users after the move during the 30-day grace period.

Sources

Want this scoped for your environment?

Book a free consultation. After discovery you get a written plan with scope, pricing (fixed fee, hourly, retainer or block of hours) and a timeline.

Book a free consultation