Mailflow Co-existence between Google Apps and Office 365 during IMAP Migration

This article will explain how to create mail flow coexistence between disparate IMAP source and Exchange Online destination.

Use case:

  1. Customer wants a mailflow co-existence between hosted email e.g. Gmail and Exchange Online during mailbox migration phase.
  2. Customer has on-premises Exchange Server but does not want to create hybrid environment or have a situation where hybrid configuration is not feasible.
  3. Customer plans to migrate mailboxes, calendar, contacts, resources and distribution groups to Exchange Online in phases.
  4. Customer does not want a cutover migration to Exchange Online.

Source Environment:

  1. Email Domain:
  2. Migration Method: IMAP
  3. Source Infrastructure: On-premises Microsoft Exchange or Hosted Gmail

Destination Environment:

  1. Office 365 Tenant:
  2. Default Domain:
  3. Email Domain:
  4. CatchAll Domain or Subdomain:

Migration Method:

  • Pre-stage: In pre-stage migration, data will be pre-filled to a place holder mailbox then migrate delta changes.
  • Backfill: In backfill method, data will be back filled to a real mailbox after cutover.

Prepare Source Email Domain:

  1. Add Proxy address or alias to all mailboxes.

To add proxy address, create a CSV file with the below header and run the scripts

Name, EmailAddress,

Import-Csv c:\data.csv | Foreach{

$maileg = Get-Mailbox -Identity $_.Name

$maileg.EmailAddresses += $_.emailaddress

$maileg | Set-Mailbox -EmailAddresses $_.emailaddress


  1. Create target address or forwarding address to all mailboxes. To add target address, create a CSV file with the below header and run the script

CSV Headers are Mailbox, ForwardTo,,

Import-CSV “C:\CSV\Users.csv” | ForEach {Set-Mailbox -Identity $_.mailbox -ForwardingAddress $_.forwardto}

  1. Send & Receive Connector

If you have strict mailflow condition on the on-premises environment or hosted environment, you may have to create a send connector and receive connector to allow Office 365 email in both directions.

  1. MX record still pointed to source environment.

Prepare Exchange Online

  1. Create Office 365 tenant:
  2. Add customer domain e.g. on the Office 365 portal and validate the domain
  3. Go to Office 365 ECP, Select Mailflow, Click Accepted Domain, Select, Click Edit and set the domain to Internal Relay
  4. Go to Office 365 ECP, Select Recipient, Go to Groups, Create a distribution group and add all users to the distribution group. To find a script to do the job, refer to step3 of post migration section of this article. replace remove-distributiongroupmember to add-distributiongroupmember on the script.
  5. Go to Office 365 ECP, Select Mailflow, Connectors, create an Outbound Send Connector to send email from Office 365 to Your organisation email server. When creating this Connector select the smart host option and on the smart host window, type the Public IP Address or FQDN of MX record of
  6. Go to Office 365 ECP, Select Mailflow, Rules, create a rule to forward any inbound emails coming to and member of special distribution group created in step 4 to be forwarded to the send connector you have created in previous steps 5.
  7. Enable Mailflow for subdomain or catchall domain i.e. Set-AcceptedDomain -Identity -MatchSubdomains $true

Mailflow during migration phase

When an Exchange Online mailbox user1@domain send mail to (On-premises/hosted Gmail), as user2 does not exist at Exchange Online side, and the domain: set as “Internal Relay” under “Accept domain” configuration, so the message will delivery to on-premises/Gmail through special outbound connector.

Post Migration:

Once you have migrated a batch of mailboxes, you have to remove proxy address and forwarding address from that batch of source mailboxes on the source email domain.

  1. Remove Proxy Address from Source Environment

CSV Headers are Name and EmailAddress,

Import-Csv C:\CSV\ProxyAddress.csv | Foreach{

$maileg = Get-RemoteMailbox -Identity $_.Name

$maileg.EmailAddresses += $_.emailaddress

$maileg | Set-Mailbox -EmailAddresses @{Remove=$_.EmailAddress} }


  1. Remove Forwarding address from Source Environment

CSV headers are Mailbox, ForwardTo,

Import-CSV “C:\CSV\Users.csv” | ForEach {Set-Mailbox -Identity $_.mailbox -ForwardingAddress @{Remove=$_.forwardto}}

  1. Remove the batch of mailboxes from the distribution groups once migrated to Office 365.

CSV Headers are

Identity, Members


Import-Csv “C:\CSV\RemoveMembers.csv” | foreach{Remove-DistributionGroupMember -Identity $_.identity -Member $_.members}

  1. Delete special Distribution Group, Maiflow rule and Outbound Connector created on the step 4, step 5 and step 6 after MX record cutover to Office 365.


On-prem to Office 365 Migration: PowerShell Script Collection

Connect to Azure Active Directory PowerShell without Password Prompt

#Use Case: Log on to Office 365 tenant without typing credentials.


$Password=ConvertTo-SecureString -String “MyPassword” -AsPlainText -Force

$O365CREDS= New-Object –TypeName “System.Management.Automation.PSCredential” –ArgumentList $User, $Password

#$O365CREDS = Get-Credential -Username Raihan@tenant.OnMicrosoft.Com

$SESSION = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri -Credential $O365CREDS -Authentication Basic -AllowRedirection

Import-PSSession $SESSION

Connect-MsolService -Credential $O365CREDS

Create New UPN Suffix

#Use Case: Create New UPN Suffix in Active Directory to match email domain.

Get-ADForest | Set-ADForest -UPNSuffixes @{add=””}

 Changing  UPN Suffix from CSV Input


#Use Case: Changing .local domain to email domain before the Office 365 migration.

#CSV header of input file is Loginid and each row containing one samaccountname.

 $oldSuffix = ‘’

$newSuffix = ‘’

Import-CSV userlist.csv | ForEach-Object {

$usr = get-aduser $_.loginid |Select userprincipalname, samaccountname

$newUpn = $usr.UserPrincipalName.Replace($oldSuffix,$newSuffix)

Set-ADUser -identity $usr.samaccountname -UserPrincipalName $newUpn -Verbose


 Changing UPN Suffix to Match Email Address

#Use Case: To match UPN suffix with primary email address on the general properties of Active Directory users.

Step 1: Export all UserPrincipalNames and Email Addresses from the AD to a CSV File.

Get-AdUser -Filter * -Properties UserPrincipalName, Name, EmailAddress | Select-Object UserPrincipalName, Name, EmailAddress | Export-CSV -Path C:\MyADUsers.csv -NoTypeInformation

Step 2: Use that CSV file to bulk change the UserPrincipalNames to match those Email Addresses.

CSV Headers are UserPrincipalName and EmailAddress

#Script to Change the UPN on the Active Directory#

#This script should run from an Active Directory Module for Windows PowerShell#

$UserCount = 0

Import-Csv -Path C:\MyADUsers.csv | ForEach-Object {

$UPN = $_.UserPrincipalName

Write-Host “Working on user:” $UPN

Get-ADUser -Filter {UserPrincipalName -Eq $UPN} | Set-AdUser -userprincipalname $_.EmailAddress

$usercount = $usercount +1


Write-Host “Number of users on your CSV: $UserCount”

Write-Host “UPN’s Changed”

 Changing UPN to Match SMTP

  #Use Case: Select all users in a domain and assign new UPN in bulk

Get-ADUser -Filter {mail -like “*”} -Properties Mail | Foreach { Set-ADUser $_ -UserPrincipalName $_.mail }

Above command will copy primary SMTP of each user and make that SMTP to match UPN suffix. To complete this task, you must pre-populate primary SMTP before you run this command.

 Changing UserName to FirstName.LastName

#Use Case: If you have a scenario where username is but your username should match the SMTP which is . In this scenario you can extract all username from Active Directory, create a CSV or txt file with one column with just username and no then the below script will modify username from FirstName to

Get-Content .\users.csv | foreach { .\Update-Username.ps1 –Username $_ –UPNSuffix -LogFile .\changes.txt -WhatIf }


Add Alias and Set as Primary SMTP


#Use case: You have synchronized all users from on-prem Active Directory to Azure Active Directory but users email address is showing default domain e.g. Now you want to add a alias and set that alias as primary SMTP to match email domain. 

 Import-Csv c:\data.csv | Foreach{

$maileg = Get-Mailbox -Identity $_.Name

$maileg.EmailAddresses += $_.emailaddress

$maileg | Set-Mailbox -EmailAddresses $maileg.EmailAddresses -PrimarySmtpAddress $_.emailaddress


 Assign Office 365 licenses from CSV File Input

#Use Case: Assign licenses in bulk. 

Step1: Find Current Sku

Get-MsolAccountSkuId to find out current Sku

Step2: Create a CSV file with UserPrincipalName as header e.g.

Step3: Run the command.

$path= Import-Csv -Path “C:\CSV\E1Licenses.csv”

foreach ($item in $path){

$MSOLUserName= $item.UserPrincipalName

$AccountSkuId = “tenant:STANDARDPACK”

$UsageLocation = “AU”

$LicenseOptions = New-MsolLicenseOptions -AccountSkuId $AccountSkuId

Set-MsolUser -UserPrincipalName $MSOLUserName -UsageLocation $UsageLocation

Set-MsolUserLicense -UserPrincipalName $MSOLUserName -AddLicenses $AccountSkuId  -LicenseOptions $LicenseOptions



  • For E1 license is StandardPack and for E3 license is EnterprisePack
  • For Country Code, use ISO 3166 two-letter country-code standard e.g. Australia is AU

 Reclaim Office 365 Licenses

Step1: Export Last Logon to Office 365 in a SSO environment

Follow the URL to Extract last log on report to make sure user did not log on recently and active.

Step2: Create a CSV file with a header UserPrincipalName

Step3: Remove Office 365 Licenses from CSV File Input

$path= Import-Csv -Path “C:\CSV\E1NA.csv”

foreach ($item in $path){

$MSOLUserName= $item.UserPrincipalName

$AccountSkuId = “Tenant:ENTERPRISEPACK”

Set-MsolUserLicense -UserPrincipalName $MSOLUserName -RemoveLicenses $AccountSkuId


 Import Contact from On-prem to Office 365 via CSV File

#Use Case: This script is to import all the contact from on-premises Exchange to Office 365 from a CSV input.

Step1: Run Export all mail contact Get-MailContact | Export-Csv c:\CSV\MailContact.CSV 

Step2: Create a CSV file with CSV headers are Name,DisplayName,ExternalEmailAddress,FirstName,LastName

 Step3: Import Mail Contact  

Import-Csv | ForEach {New-MailContact -Name $_.Name -DisplayName $_.Name -ExternalEmailAddress $_.ExternalEmailAddress -FirstName $_.FirstName -LastName $_.LastName}

 Import Room Mailboxes from On-prem to Office 365 via CSV input

 Step1: Export Room Mailboxes  Get-Mailbox -RecipientTypeDetails RoomMailbox | Export-Csv c:\CSv\RoomMailboxes.csv Get-Mailbox -RecipientTypeDetails EquipmentMailbox | Export-Csv c:\CSv\EquipmentMailboxes.csv

 Step2: Create CSV file with header Name,Alias,PrimarySMTPAddress

Step3: Run the following command to import Room Mailbox

Import-Csv “C:\Scripts\RoomMailboxes.csv” | foreach-object { New-Mailbox -Name $_.Name -Alias $_.Alias -PrimarySmtpAddress $_.Address -Room }

 Assign Shared Mailboxes Permission to Match on-prem Shared Mailboxes

Step1: Export Shared Mailbox Full Access Permision

Get-Mailbox -RecipientTypeDetails SharedMailbox | Get-MailboxPermission | where { ($_.AccessRights -eq “FullAccess”) -and ($_.IsInherited -eq $false) -and -not ($_.User -like “NT AUTHORITY\SELF”) }

Step2: Export Shared Mailbox SendAs Permision

Get-Mailbox -RecipientTypeDetails SharedMailbox | Get-ADPermission | Where {$_.ExtendedRights -like “Send-As” -and $_.User -notlike “NT AUTHORIT\SELF” -and $_.Deny -eq $false} | ft Identity,User,IsInherited -AutoSize

Step3: Prepare two CSV file with header like Name,User where name is the username and user primary SMTP of shared Mailbox.

Step4: Assign SendAs Permission to Shared Mailboxes

$Mailboxes = import-csv C:\CSV\Mailboxes1.csv

Foreach ($Mailbox in $Mailboxes) {Add-RecipientPermission -Identity $Mailbox.Name -Trustee $Mailbox.User -AccessRights “SendAs”}

Step5: Assign Full Access Permission to Shared Mailboxes

$Mailboxes = import-csv C:\CSV\Mailboxes1.csv

Foreach ($Mailbox in $Mailboxes) {Add-MailboxPermission -Identity $Mailbox.Name -user $Mailbox.User -AccessRights ‘FullAccess’ -InheritanceType All}

 Import DL from on-prem to office 365 including Memberships

Download and install PowerShell module from this URL

Step1: Extract list of AD Groups

Get-ADGroupMember -Id “Group Name” | Export-CSV c:\temp\GroupOutput.CSV –NoTypeInformation

Step2: Extract AD Group’s memberships

$groups = Get-Content c:\temp\ADGroupsAdmin.csv           

foreach($Group in $Groups) {                    

Get-ADGroupMember -Id $Group | select  @{Expression={$Group};Label=”Group Name”},* | Export-CSV c:\temp\GroupsInfo.CSV -NoTypeInformation -Append           


Step3: Export ManagedBy Properties of DL

$DL = ‘OU=example,DC=Domain,DC=com’

$DL | ForEach {Get-ADGroup -Filter * -Properties ManagedBy -SearchBase $_ } |

 Select Name, ManagedBy | Sort -Property Name | Out-File C:\ManagedBy.csv

Step4: Create Distribution Group in Bulk

CSV Headers are Name,DisplayName,Alias,Address,Type

Import-CSV “C:\CSG\distributiongroup.csv” | foreach {New-DistributionGroup -Name $ -DisplayName $_.DisplayName -Alias $_.Alias -PrimarySmtpAddress $_.Address -Type $_.Type}

Step5: Add Members to Distribution Group in Bulk

CSV headers are Indentity,Members

Import-Csv “C:\CSG\addmem1.csv” | foreach{Add-DistributionGroupMember -Identity $_.identity -Member $_.members}

Step6: Add ManagedBy properties of Distribution Groups

CSV Headers are GroupName,ManagedBy,User

$list=import-csv C:\AddDistributionGroupOwnerList.csv

Foreach ($i in $list) {

 $grp=get-distributiongroup $i.groupname


 $newuser=get-user $i.user


 Set-distributiongroup $grp -managedby $newmanage -bypasssecuritygroupmanagercheck


 Enable remote Mailboxes in Bulk

This script is useful in hybrid environment when you don’t want to create a mailbox on the on-prem server and then migrate to Office 365. Instead you enable remote mailbox and assign Office 365 licenses to user and create the mailboxes in the Office 365 tenant.  

$Users = Import-csv C:\CSv\EnableRemoteMailbox.csv$Users | ForEach-Object {Enable-RemoteMailbox -identity $_.userprincipalname -RemoteRoutingAddress ($_.samaccountname+’’)} 

Add Proxy Address to the On-prem Mailboxes

This script is very handy if you would like to add alias to all mailboxes in bulk. Alias or proxy address can be used for various reason including mailflow co-existence between disparate mail systems to Office 365 address during IMAP migration.

CSV Headers are Name,ProxyAddresses

 Import-Csv C:\AddressList.csv | ForEach-Object {

  $name = $_.Name

  $proxy = $_.ProxyAddresses -split ‘;’

  Set-Mailbox -Identity $name -EmailAddresses @{add= $proxy}


 Setup Forwarding Address on the On-prem Server

This script is to create forwarding address or target address in bulk. Target address is used to configure mailflow co-existence between disparate mail systems to Office 365 address during IMAP migration.

CSV Headers are Mailbox,ForwardTo

Import-CSV “C:\CSV\Users.csv” | ForEach {Set-Mailbox -Identity $_.mailbox -ForwardingAddress $_.forwardto}

Terms & Conditions:

Before you run any script from any internet source, make sure you understand the risks associated with the script. Understand what has been written on the script, test and validate the script then you run the script. These script does not come with at-fault warranty. These scripts come with As is. Use one or all the scripts when necessary and if the my scenario matches yours. Good luck!