Exchange OnlineHow-to

FortiMail to Exchange Online, part 2: IMAP mailbox migration, waves and cutover

Move FortiMail server-mode mailboxes to Exchange Online with IMAP migration: open IMAP safely, build the endpoint and CSVs, run a pilot and waves, cut over and clean up without losing mail.

In part 1 we sized the project: about 400 active mailboxes and 100 former employees' mailboxes, 4 TB in total, on a FortiMail unit running in server mode. This part moves the active mailboxes with the IMAP migration built into Exchange Online. I'll prepare FortiMail and the tenant, create the endpoint and the CSV files, run a pilot and the waves, then cut over and finish without losing the mail that arrives on the last day. The leavers use the same mechanism with a different target, which is part 3.

How this guide is organized: How IMAP migration works here → Prerequisites → Step-by-step → Verify the migration → Tips and gotchasFlow diagram of the article's sections in reading order: 1. How IMAP migration works here. 2. Prerequisites. 3. Step-by-step (5 steps: Prepare FortiMail; Create the endpoint in Exchange Online; Build the CSV files and the waves; Run the pilot, then the waves; Cut over). 4. Verify the migration. 5. Tips and gotchas. Toolbox: Get-EXOMailboxStatistics, imap.contoso.com, EmailAddress, UserName, autodiscover.contoso.com.1How IMAPmigration wor…2Prerequisites3Step-by-step4Verify themigration5Tips andgotchas1Prepare FortiMail2Create theendpoint in Excha…3Build the CSV filesand the waves4Run the pilot, thenthe waves5Cut overTOOLBOXGet-EXOMailboxStatisticsimap.contoso.comEmailAddressUserNameautodiscover.contoso.comHow this guide is organized: How IMAP migration works here → Prerequisites → Step-by-step → Verify the migration → Tips and gotchasFlow diagram of the article's sections in reading order: 1. How IMAP migration works here. 2. Prerequisites. 3. Step-by-step (5 steps: Prepare FortiMail; Create the endpoint in Exchange Online; Build the CSV files and the waves; Run the pilot, then the waves; Cut over). 4. Verify the migration. 5. Tips and gotchas. Toolbox: Get-EXOMailboxStatistics, imap.contoso.com, EmailAddress, UserName, autodiscover.contoso.com.1How IMAP migration works here2Prerequisites3Step-by-step1Prepare FortiMail2Create the endpoint in Exchange Online3Build the CSV files and the waves4Run the pilot, then the waves5Cut over4Verify the migration5Tips and gotchasTOOLBOXGet-EXOMailboxStatisticsimap.contoso.comEmailAddressUserNameautodiscover.contoso.com
At a glance: how this guide is organized · 5 steps · 5 key settings and tools

How IMAP migration works here#

How an IMAP migration from FortiMail runs, start to finishStep 1: Prepare FortiMail. IMAPS open to Exchange Online, limits raised, known passwords Step 2: Test and create the endpoint. Test the IMAP connection, then create the endpoint Step 3: Pilot batch. Measure GB per hour and fix errors before the waves Step 4: Waves until Synced. Full copy first, then an incremental sync every 24 hours Step 5: Switch MX and clients. New mail lands in Exchange Online; Outlook signs in Step 6: Keep syncing for 72 hours. Late mail delivered to FortiMail is still copied Step 7: Remove the batches. After a sync newer than the MX change; lift the retention hold1Prepare FortiMailIMAPS open toExchange Online, limitsraised, knownpasswords2Test and create theendpointTest the IMAPconnection, then createthe endpoint3Pilot batchMeasure GB per hourand fix errors before thewaves4Waves until SyncedFull copy first, then anincremental sync every24 hours5Switch MX andclientsNew mail lands inExchange Online;Outlook signs in6Keep syncing for 72hoursLate mail delivered toFortiMail is still copied7Remove thebatchesAfter a sync newer thanthe MX change; lift theretention holdHow an IMAP migration from FortiMail runs, start to finishStep 1: Prepare FortiMail. IMAPS open to Exchange Online, limits raised, known passwords Step 2: Test and create the endpoint. Test the IMAP connection, then create the endpoint Step 3: Pilot batch. Measure GB per hour and fix errors before the waves Step 4: Waves until Synced. Full copy first, then an incremental sync every 24 hours Step 5: Switch MX and clients. New mail lands in Exchange Online; Outlook signs in Step 6: Keep syncing for 72 hours. Late mail delivered to FortiMail is still copied Step 7: Remove the batches. After a sync newer than the MX change; lift the retention hold1Prepare FortiMailIMAPS open to Exchange Online, limits raised, knownpasswords2Test and create the endpointTest the IMAP connection, then create the endpoint3Pilot batchMeasure GB per hour and fix errors before the waves4Waves until SyncedFull copy first, then an incremental sync every 24 hours5Switch MX and clientsNew mail lands in Exchange Online; Outlook signs in6Keep syncing for 72 hoursLate mail delivered to FortiMail is still copied7Remove the batchesAfter a sync newer than the MX change; lift theretention hold
Figure 1 · Process How an IMAP migration from FortiMail runs, start to finish. Exchange Online pulls mail from FortiMail's IMAP service: a full copy first, then a sync every 24 hours, so the cutover only moves the last day's mail. Remove batches only after the final syncs.

Exchange Online connects to FortiMail's IMAP service with each mailbox's credentials and copies the mail folders into the matching Exchange Online mailbox. After the first full copy, the batch runs an incremental sync once every 24 hours until you remove it. Users keep working on FortiMail the whole time; the real switch is the MX record change at cutover.

Microsoft documents the limits, and they shape the plan:

  • Only mail folders move: no contacts, calendar items or tasks.
  • At most 500,000 items per mailbox are migrated, newest first.
  • Messages larger than 35 MB aren't migrated.
  • Folders with a forward slash (/) in their name aren't migrated.

Microsoft also recommends disabling messaging records management (MRM) and archival policies on the target mailboxes during a migration: anything those policies move or delete is reported as missing, which hides real data loss. In practice, don't enable archive mailboxes until the last sync is done, and pause any retention that deletes or moves mail in the targets.

Prerequisites#

  • Your domain added and verified in Microsoft 365, and the users created and licensed: the target mailboxes must exist before a batch can use them.
  • Exchange Online PowerShell (the ExchangeOnlineManagement module) and an admin role that includes the migration permissions.
  • FortiMail admin access, and a public host name for its IMAP service (for example imap.contoso.com) with a trusted certificate that matches it.
  • The MX record's TTL already lowered to 3,600 seconds.
  • The mapping sheet from part 1: FortiMail account, Microsoft 365 address, size and wave.

Step 1: Prepare FortiMail#

Open IMAP to Exchange Online, and only to it#

The migration service connects from Microsoft's datacenters, so FortiMail's IMAP port (993 for IMAP over SSL/TLS) must accept connections from the internet. Microsoft's IMAP migration guidance points to the Exchange Online URLs and IP address ranges list for the addresses to allow. Restrict the firewall rule to those ranges, and close it again when the project ends.

Raise the connection limits#

Microsoft's advice for IMAP migrations is to raise three limits before you start, on the IMAP server and on any firewall in front of it: total connections, connections per user and connections per IP address. Exchange Online opens many IMAP sessions in parallel, and a firewall that hasn't been told to expect them can treat that as an attack.

Decide how the migration signs in#

The CSV file must contain credentials that open each FortiMail mailbox. Microsoft supports two approaches: the user's own credentials, or an administrator (super-user) account where the IMAP server supports one. Microsoft's documented administrator formats cover servers such as Exchange, Dovecot and Mirapoint, and FortiMail isn't among them, so unless Fortinet documents delegated IMAP access for your firmware, plan for per-user credentials:

  • Local FortiMail passwords. Just before a wave starts, set each user in it to a known migration password, tell them, and stop them changing it until cutover. Microsoft warns that if users change their password after the first sync, the following syncs fail.
  • Passwords checked against Active Directory. The migration password is then the user's directory password, and also their Microsoft 365 password if you synchronize password hashes. Schedule the reset with each user, or consider a third-party tool with a different access method.
  • Former employees. Nobody uses these mailboxes, so a reset costs nothing (part 3).

Treat the CSV files as secrets: keep them encrypted, never email them, and delete them when the wave is finished.

Rescue what IMAP won't move#

  • Address book. Export the global and domain address books from Domain & User › Address Book (CSV or vCard) and recreate the entries you still need as mail contacts in Exchange Online.
  • Personal contacts and calendars. If users keep them in FortiMail webmail, ask them to export them before cutover with the export your webmail version offers, and import them into Outlook afterwards.
  • Quarantine. Release anything users still need from their FortiMail quarantine before cutover. Don't plan on migrating quarantined mail.
  • Backup. Take a FortiMail mailbox backup; Fortinet supports NFS, SMB, iSCSI, SSH and USB targets. It's a restore point for FortiMail, not an import format for Exchange, but it's your safety net until the project closes.

Step 2: Create the endpoint in Exchange Online#

PowerShell
Connect-ExchangeOnline

# Can Exchange Online reach FortiMail's IMAP service?
Test-MigrationServerAvailability -IMAP -RemoteServer imap.contoso.com -Port 993 -Security Ssl

# Create the endpoint with modest concurrency to start with
New-MigrationEndpoint -IMAP -Name "FortiMail-IMAP" -RemoteServer imap.contoso.com -Port 993 -Security Ssl `
    -MaxConcurrentMigrations 20 -MaxConcurrentIncrementalSyncs 10
Get-MigrationEndpoint "FortiMail-IMAP" | Format-List EndpointType, RemoteServer, Port, Security, Max*

Then keep retention away from the targets during the copy. Retention hold pauses the Exchange (MRM) retention policy on a mailbox. If you also use Microsoft Purview retention policies that delete mail after a number of years, exclude the migration targets or delay those policies until the migration is over, or years-old mail can be deleted soon after it arrives.

PowerShell
Import-Csv "C:\Migration\wave01.csv" | ForEach-Object {
    Set-Mailbox -Identity $_.EmailAddress -RetentionHoldEnabled $true
}

Step 3: Build the CSV files and the waves#

Each CSV needs three columns: EmailAddress (the Exchange Online mailbox), UserName (the name FortiMail expects at IMAP sign-in; check it with an IMAP client first, it's often the full address) and Password. A file can hold up to 50,000 rows, but smaller batches are easier to watch and to retry.

Text
EmailAddress,UserName,Password
amal.hassan@contoso.com,amal.hassan@contoso.com,MIGRATION-PASSWORD-1
karim.osman@contoso.com,karim.osman@contoso.com,MIGRATION-PASSWORD-2

A wave plan that works well for 400 mailboxes:

  • Pilot: five to ten mailboxes, including IT staff, one heavy user and one of the largest mailboxes.
  • Waves of 40 to 60 mailboxes: largest first, so the long copies start early; executives once the process is proven.
  • Leavers: separate batches (part 3).

Look at the folder names FortiMail exposes over IMAP before you exclude anything. Junk and trash folders are the usual candidates for -ExcludeFolders; the names in the example below are placeholders for whatever your FortiMail shows.

Step 4: Run the pilot, then the waves#

PowerShell
New-MigrationBatch -Name "Wave00-Pilot" -SourceEndpoint "FortiMail-IMAP" `
    -CSVData ([System.IO.File]::ReadAllBytes("C:\Migration\wave00.csv")) `
    -ExcludeFolders "Junk","Trash" -NotificationEmails "migration-team@contoso.com" -AutoStart

# Batch and per-mailbox progress
Get-MigrationBatch | Format-Table Identity, Status, TotalCount
Get-MigrationUser -BatchId "Wave00-Pilot" | Format-Table Identity, Status, SyncedItemCount, SkippedItemCount

# Errors and skipped items for one mailbox
Get-MigrationUserStatistics -Identity amal.hassan@contoso.com -IncludeSkippedItems -IncludeReport |
    Format-List Status, Error, SkippedItems

A mailbox shows Synced when its first full copy is done; from then on it gets an incremental sync every 24 hours. Use the pilot to measure throughput: check each pilot mailbox's size in Exchange Online at intervals with Get-EXOMailboxStatistics -Identity amal.hassan@contoso.com | Format-List TotalItemSize, add up the gigabytes copied across the batch per hour, and put that figure into the estimate from part 1.

Raise concurrency in steps while you watch FortiMail's CPU, disks and IMAP sessions, and the experience of the users still working on it. Microsoft's guidance is to start small and increase while you monitor the source; an endpoint allows up to 100:

PowerShell
Set-MigrationEndpoint -Identity "FortiMail-IMAP" -MaxConcurrentMigrations 40

For errors at the endpoint, in the CSV or for individual users, see my quick reference for Exchange Online migration batch errors.

Step 5: Cut over#

Cut over when every batch is Synced and has completed a recent incremental sync. Then, in this order:

  1. Switch the MX record to Exchange Online, as described in part 4. Leave FortiMail running and accepting mail: senders with the old MX record cached keep delivering to it for a while, and the incremental syncs copy those messages across.
  2. Point Autodiscover at Exchange Online with a CNAME record from autodiscover.contoso.com to autodiscover.outlook.com.
  3. Move the clients. Users sign in to Outlook with their Microsoft 365 account (a new profile in classic Outlook, or the new Outlook), install Outlook on their phones and remove the old IMAP or POP accounts, so nobody keeps filing mail into FortiMail.
  4. Keep syncing. Microsoft recommends waiting at least 72 hours after the MX change before you delete a batch, and checking that the batch synced at least once after mail started arriving in Exchange Online: its last synced time, under Migration in the Exchange admin center, must be later than the switch.
  5. Remove the batches and lift the retention hold.
PowerShell
Remove-MigrationBatch -Identity "Wave00-Pilot"
Get-MigrationBatch -Identity "Wave00-Pilot"    # shows Removing, then an error once it's gone

Import-Csv "C:\Migration\wave01.csv" | ForEach-Object {
    Set-Mailbox -Identity $_.EmailAddress -RetentionHoldEnabled $false
}

Verify the migration#

Compare a sample of mailboxes with FortiMail, folder by folder:

PowerShell
Get-EXOMailboxFolderStatistics -Identity amal.hassan@contoso.com |
    Format-Table FolderPath, ItemsInFolder, FolderSize -AutoSize
  • Folder counts match the counts an IMAP client shows on FortiMail, allowing for excluded folders and skipped items.
  • Every skipped item in the batch reports is explained (usually oversize or damaged messages).
  • New internet mail arrives in Exchange Online: message trace shows it (part 4 has the commands).
  • Users can open old mail, find their sent items and search across the migrated folders.

Tips and gotchas#

  • Don't change addresses mid-migration. Microsoft warns not to delete target mailboxes or change their SMTP addresses until the batch is complete and deleted.
  • Rename folders that contain a slash on FortiMail before the batch, or their mail stays behind.
  • Deal with oversize mail separately. Microsoft suggests asking users to save very large messages and attachments before the move; OneDrive is a better home than a USB stick.
  • Very large or very full mailboxes. Over 100 GB or 500,000 items, IMAP alone leaves mail behind; use Large Mailbox Onboarding or a PST import for the rest (part 5).
  • POP3 users have little on the server. Import their PST files instead (part 5).
  • Leave FortiMail alone until the rollback window and the archive decision are closed. Keep it powered, backed up and in server mode: Fortinet warns that changing its operation mode resets most of the configuration.

References#

Written and checked against current Microsoft Learn documentation. Test changes with a pilot group before rolling them out to everyone, and if an admin center path has moved since, search for the setting name instead.

Spotted a mistake, or did this fix work differently for you? Email me or message me on LinkedIn — corrections are credited in the article.

Written by

Omer Eltayeb

M365 Subject Matter Expert, former Microsoft Cloud Solutions Architect, Microsoft Certified Trainer and Microsoft Innovative Educator Expert (2024–26) and Microsoft Elevate Educator Expert (2026–27). I share practical, step-by-step guides, study plans, scripts and toolkits for Microsoft Intune, Configuration Manager, Microsoft Entra ID, Microsoft Defender, Exchange and Microsoft 365 with the community.

Microsoft Certified Trainer (MCT) 2026Microsoft Innovative Educator Expert 2025–2026Microsoft Elevate Educator Expert 2026–2027ISC2 Certified Information Systems Security Professional (CISSP)Microsoft 365 Certified: Enterprise Administrator Expert (MS-102)