Key takeaway: To move on-premises Exchange mailbox data into Microsoft 365 without a hybrid mailbox move, export each mailbox to PST, upload the PST files to the Azure Blob storage that Microsoft provides for your tenant using AzCopy, and let the Microsoft Purview Import service load them into mailboxes. You do not need an Azure subscription. The Azure Blob tools in most migration guides (Storage Mover, Data Box, zip-and-unzip pipelines) are for moving files into storage accounts you own, and they do not feed Exchange Online directly.

Most advice about "using Azure Blob Storage for a migration" is written for file data. Exchange is different: the destination is a mailbox, not a container. This guide explains when the blob-based PST import is the right tool, then walks through every step from the on-premises Exchange server to a finished mailbox in Microsoft 365, including the checks that are easy to skip. For a related method that applies to Public Folders, see Migrate Exchange Public Folders to a Shared Mailbox.

What "Blob Storage" Means in an Exchange Migration

Two different things get called "Azure Blob storage," and mixing them up causes most of the confusion:

This article is about the first. The last section covers the second.

When to Use This Method, and When Not To

SituationBest approach
Live mailboxes, hybrid configured, users must keep workingHybrid mailbox moves. They keep mail flow, free/busy, and Outlook profiles intact
Live mailboxes, small organization, no hybridCutover or staged migration, or a third-party migration tool
Old archives, PSTs scattered on file shares and laptopsPST import (this guide)
Decommissioning an Exchange server and keeping the historyPST import
Former employees whose data must be keptPST import into an inactive mailbox
A user's cloud archive when their primary mailbox is still on-premisesPST import into the cloud archive
Public Folder contentNot supported by the Import service. Move it to a mailbox first (see the Public Folders article linked above)
Calendars and contacts that must stay synchronized liveA mailbox move, not PST

The PST method copies a point-in-time snapshot. Mail that arrives after the export is not included, so for live mailboxes you would need a second export and import of the gap, or you would use a mailbox move instead. Treat PST import as the right tool for history, not for a live cutover.

What About Compressing the Data First?

A common idea is to zip the data locally, upload the smaller files to Azure, and unzip them in the cloud to get around a slow or throttled link. For Exchange data, that does not work the way people hope:

Better ways to get more out of a slow link are described in Step 6: trim what you export, schedule uploads off-hours, cap the bandwidth so you do not starve the business, and let AzCopy resume interrupted transfers. Use the version of AzCopy that the Purview Import page links to. Microsoft does not support other versions for this process.

Limits to Know Before You Start

These come from Microsoft's current documentation for the Import service. Check the live page before you plan around them.

LimitValue
PST file sizeKeep each file at or below 20 GB. Larger files hurt import performance
PST file namesMust be unique across the import job, and are case-sensitive in the mapping file
Rows per mapping file500. For more PSTs, create more mapping files and more jobs
Import speedAbout 24 GB per day per mailbox, not guaranteed. Different mailboxes import in parallel. PSTs for the same mailbox import one at a time
Archive importsNo more than 100 GB into a user's archive in a single import. Split larger imports and allow the archive to auto-expand between them
Item sizeItems over 150 MB are skipped, because that is the Exchange Online message limit
Folder depthPSTs with 300 or more nested folder levels cannot be imported
FormatsUnicode PST is preferred. ANSI is supported (with a code page option for double-byte languages). Outlook 2007 and later
Public folders and groupsCannot be targets
Staging area cleanupUploaded PSTs are removed automatically 30 days after the most recent import job was created. You cannot delete them yourself
Retention holdTurned on for the mailbox after import, indefinitely, until you turn it off
Cost and availabilityNetwork upload is free and available to all commercial licensing agreements. Drive shipping has costs and is limited to certain agreements and regions

Step 1: Plan and Inventory the Source

Capture the size and item count of every mailbox, including archives. These numbers are your reconciliation baseline at the end.

# Run in the Exchange Management Shell Get-Mailbox -ResultSize Unlimited | ForEach-Object { $p = Get-MailboxStatistics $_ $a = if ($_.ArchiveDatabase) { Get-MailboxStatistics $_ -Archive } else { $null } [pscustomobject]@{ Email = $_.PrimarySmtpAddress Items = $p.ItemCount SizeGB = [math]::Round($p.TotalItemSize.Value.ToBytes() / 1GB, 2) ArchiveItems = $a.ItemCount ArchiveGB = if ($a) { [math]::Round($a.TotalItemSize.Value.ToBytes() / 1GB, 2) } else { 0 } } } | Export-Csv C:\Migration\Source-Inventory.csv -NoTypeInformation

From the inventory, decide:

Step 2: Prepare Microsoft 365

  1. Create the destination mailboxes and assign licenses. Users must exist in Entra ID with an Exchange Online mailbox before you import. Directory synchronization from on-premises, if you use it, must have completed.
  2. Enable archives for anyone whose PSTs will go to the archive. The import fails for that user if the archive is not enabled:
Connect-ExchangeOnline Enable-Mailbox jsmith@contoso.com -Archive # For archives that may exceed the base size, make sure auto-expanding archiving is on Set-OrganizationConfig -AutoExpandingArchive
  1. Give the importing admin the right roles. You need the *Mailbox Import Export* role and the *Mail Recipients* role in Exchange Online, or Global Administrator. No role group has *Mailbox Import Export* by default. A dedicated role group keeps this narrow:
New-RoleGroup -Name "PST Import" ` -Roles "Mailbox Import Export","Mail Recipients" ` -Members admin@contoso.com
  1. Check mailbox size limits. Imported data counts toward the mailbox and archive quotas. Make sure the licenses provide enough room.
  2. Decide how to handle retention. The Import service puts the mailbox on retention hold after import. If your tenant has retention policies that delete or archive old mail, plan to review them (see Step 10).

Step 3: Export Mailboxes from On-Premises Exchange to PST

Exchange has a server-side cmdlet, New-MailboxExportRequest, that writes a mailbox to a PST on a network share. It needs a few things set up first.

  1. Give your admin account the export role on the on-premises server:
New-ManagementRoleAssignment -Role "Mailbox Import Export" -User "Administrator"

Log off and on again (or restart the Exchange Management Shell) so the new role takes effect.

  1. Create a staging share with enough free space for all the PSTs. Grant the Exchange Trusted Subsystem security group *Read/Write* (modify) permission on both the share and the folder. Without it, the export fails with an access denied error. Also restrict access to the folder, because PSTs hold sensitive mail.
  1. Export one mailbox and watch it complete. Name the file after the email alias in lowercase, and give archive PSTs a clearly different name:
New-MailboxExportRequest -Mailbox jsmith -Name "export-jsmith" ` -FilePath "\\fs01\pst-staging\jsmith.pst" -BadItemLimit 10 New-MailboxExportRequest -Mailbox jsmith -IsArchive -Name "export-jsmith-archive" ` -FilePath "\\fs01\pst-staging\jsmith_archive.pst" -BadItemLimit 10 Get-MailboxExportRequest | Get-MailboxExportRequestStatistics | Format-Table Name, Status, PercentComplete, BytesTransferred, ItemsTransferred
  1. Split anything over 20 GB by date range, giving each part a unique name:
New-MailboxExportRequest -Mailbox jsmith -Name "export-jsmith-old" ` -ContentFilter "(Received -lt '01/01/2020')" ` -FilePath "\\fs01\pst-staging\jsmith_pre2020.pst" New-MailboxExportRequest -Mailbox jsmith -Name "export-jsmith-recent" ` -ContentFilter "(Received -ge '01/01/2020')" ` -FilePath "\\fs01\pst-staging\jsmith_2020plus.pst"
  1. Bulk export from a CSV of mailbox aliases once the pilot works:
Import-Csv C:\Migration\mailboxes.csv | ForEach-Object { New-MailboxExportRequest -Mailbox $_.Alias -Name "export-$($_.Alias)" ` -FilePath "\\fs01\pst-staging\$($_.Alias).pst" -BadItemLimit 10 }
  1. Clean up finished requests so the queue stays readable:
Get-MailboxExportRequest -Status Completed | Remove-MailboxExportRequest -Confirm:$false

Notes: exports include the Recoverable Items folder unless you add -ExcludeDumpster. Exporting many mailboxes at once loads the server, so run them in controlled batches. If a mailbox has unusually many corrupt items, the export stops after the -BadItemLimit, so review any failures rather than raising the limit blindly.

Step 4: Validate the PST Files Before You Upload

Uploading is the slow part, so catch problems first.

Step 5: Get the SAS URL and AzCopy

  1. Sign in to the Microsoft Purview portal as an account with the roles from Step 2.
  2. Go to Data lifecycle management, Microsoft 365, Import.
  3. Select New import job. Name it using lowercase letters, numbers, hyphens, and underscores only. Spaces and capitals are not allowed.
  4. Choose Upload your data.
  5. On the Import data page, choose Show network upload SAS URL, then Copy to clipboard. Save it in a protected place.
  6. Select Download Azure AzCopy. This is a single executable with nothing to install. Use this version. It is the one Microsoft supports for this process.

The SAS URL is a credential. Anyone who has it can upload to your tenant's import staging area, so treat it like a password: store it in a password manager or an encrypted file, and do not paste it into tickets or chat.

Step 6: Upload the PST Files with AzCopy

  1. Open a Command Prompt on the machine that can reach the staging share.
  2. Run AzCopy with the folder as the source. You cannot give it one PST file, and every PST in the folder is uploaded:
azcopy.exe copy "\\fs01\pst-staging" "<SAS URL>" --recursive

If you want the files in a subfolder of the staging area (helpful when you run several batches), add the subfolder to the SAS URL after ingestiondata:

azcopy.exe copy "\\fs01\pst-staging" "https://xxxx.blob.core.windows.net/ingestiondata/batch1?<SAS query>" --recursive

If you do this, remember the subfolder name. It goes into the FilePath column of the mapping file and its capitalization must match exactly. If you leave --recursive on and the source has subfolders, the files land in matching subfolders in Azure, and the FilePath has to reflect that.

  1. Quote the whole SAS URL (double quotes in Command Prompt, single quotes in PowerShell). In a batch file, the characters % and & in the URL must be written as %% and ^&.
  2. Pilot with one or two PSTs first, so you can find mistakes in the command and mapping before committing hours of upload time.
  3. Protect your business bandwidth. AzCopy will use all the bandwidth it can. Cap it during working hours and run uncapped overnight:
azcopy.exe copy "\\fs01\pst-staging" "<SAS URL>" --recursive --cap-mbps 200
  1. Handle interruptions. AzCopy writes a job log under your user profile (.azcopy). List jobs with azcopy jobs list and resume with azcopy jobs resume <job-id>, supplying the SAS token again if prompted. Run the upload from a stable server close to the data, not from a laptop that sleeps.
  2. Reduce the volume first. The Import service's filters run *after* upload, so they do not save bandwidth. To reduce data crossing the wire, use -ContentFilter in Step 3 to exclude data you do not need, and skip empty or duplicate PSTs.

When the command finishes, it prints the number of files uploaded. Compare it to the number you expected.

### Optional: See What Was Uploaded

You can attach the free Microsoft Azure Storage Explorer to the container to confirm names and subfolder paths:

  1. Choose Blob container, then the Shared access signature (SAS) authentication method.
  2. Paste the SAS URL into Blob container SAS URL. The display name fills in as ingestiondata.
  3. Review the files, then right-click ingestiondata and choose Detach when finished. If you stay attached you will get an error next time.

Storage Explorer is for viewing only. You cannot upload PSTs or delete them with it. Use AzCopy for uploads.

Step 7: Create the Mapping File

The mapping file is a CSV that tells the Import service which PST goes to which mailbox. Download Microsoft's template rather than typing the header yourself. Do not change the header row.

Workload,FilePath,Name,Mailbox,IsArchive,TargetRootFolder,ContentCodePage,SPFileContainer,SPManifestContainer,SPSiteUrl Exchange,,jsmith.pst,jsmith@contoso.com,FALSE,/,,,, Exchange,,jsmith_archive.pst,jsmith@contoso.com,TRUE,/,,,, Exchange,batch1,mjones.pst,mjones@contoso.com,FALSE,/ImportedPst,,,,
ColumnWhat to put in it
WorkloadExchange
FilePathThe subfolder in the staging area, or blank if you uploaded to the root. Never include ingestiondata. Case-sensitive, and it must match the case you used in the SAS URL
NameThe PST file name, exactly as uploaded, including case. Unique within the job
MailboxThe target email address. Use the mailbox GUID instead for an inactive or soft-deleted mailbox, or when two mailboxes share an address
IsArchiveFALSE or blank for the primary mailbox. TRUE for the archive, which must already be enabled
TargetRootFolderBlank creates an Imported folder at the root of the mailbox. / merges the PST's folders into the existing structure (Inbox into Inbox, and so on). /FolderName puts everything under that folder
ContentCodePageOnly for ANSI PSTs in double-byte languages such as Japanese. Otherwise blank
SPFileContainer, SPManifestContainer, SPSiteUrlLeave blank

Practical advice:

Step 8: Create the Import Job

  1. Return to the Import page and the job you started in Step 5 (or begin a new one, repeating the name and Upload your data choices).
  2. On step 4 of the Import data page, tick I'm done uploading my files and I have access to the mapping file, then Next.
  3. Choose Select mapping file and pick your CSV.
  4. Choose Validate. The file name turns green when it passes. If it fails, open View log. Typical errors are a name or path that does not match the upload (check the case), an archive that is not enabled, or a mailbox address that does not exist.
  5. Accept the terms and choose Save, then Close.

The job shows Analysis in progress. Select Refresh until it reads Analysis completed. Select the job to see the status of each PST.

Step 9: Filter and Start the Import

  1. Select the job, then Import to Microsoft 365.
  2. On the Filter your data page, you see the analysis: the age of items and the types of content. Choose Yes, I want to filter it before importing to trim by age, message type, or folder, or No, I want to import everything.
  3. Select Import data to start.

Watch the Status column. Large PSTs take hours, and the 24 GB-per-day guideline per mailbox applies. Different mailboxes run in parallel, so spread data across mailboxes rather than queueing many PSTs for one person. If an import fails for one user (for example, because their archive was not enabled), the rest of the job continues, so fix that row and import it in a follow-up job.

Step 10: After the Import

  1. Reconcile counts. Compare mailbox item counts in Exchange Online to the Step 1 inventory. Imported items will normally add to what is already in the mailbox, so compare the imported folder if you used a target root folder.
Get-MailboxStatistics jsmith@contoso.com | Format-List ItemCount, TotalItemSize Get-MailboxFolderStatistics jsmith@contoso.com -FolderScope All | Format-Table FolderPath, ItemsInFolder
  1. Manage the retention hold. The import turns on retention hold indefinitely, which prevents the retention policy from processing the mailbox. Decide what you want, then act. Either turn it off after a review period, or set an end date:
Set-Mailbox jsmith@contoso.com -EndDateForRetentionHold "12/31/2026" # or, once you are sure the retention settings will not purge the imported mail Set-Mailbox jsmith@contoso.com -RetentionHoldEnabled $false

If a retention policy would delete or archive mail older than a given age, lengthen that age before you lift the hold, or the old imported messages may be removed.

  1. Check the receive limit. If an imported PST contained an item over 35 MB, the service raises the mailbox's MaxReceiveSize to 150 MB.
  2. Test with users. Have a few users open Outlook and confirm the folders and attachments, find old messages through search, and check the archive.
  3. Confirm archive behavior. If a user's imported archive is large, confirm auto-expanding archiving is enabled and check the archive size.
  4. Keep a rollback copy (see below), then remove the PSTs from the staging share after the agreed period. Microsoft clears its staging container 30 days after the most recent import job.
  5. Retire the SAS URL. Delete saved copies from notes, scripts, and password managers.
  6. Decommission the source only after validation is signed off and the retention period for the backups has passed.

Mixed Environments: On-Premises and Exchange Online Together

SituationWhat to do
The mailbox is already in Exchange OnlineUse its Exchange Online address in the mapping file. This is the standard case
The mailbox is on-premises in a hybrid deploymentYou can import a PST into the user's cloud archive by using the on-premises address with IsArchive set to TRUE. For the primary mailbox, move the mailbox first
The user does not exist yetCreate and license the user, wait for the mailbox, then import
The person has leftImport into the inactive mailbox by using its GUID
A shared mailboxImport works for a shared mailbox that exists in Exchange Online. Create it first
Public Folder contentNot supported as a target. Use the Public Folders method to move it into a mailbox

If You Want Blob Storage You Own: Archive Copies and File Data

You can still use your own storage account to support the project.

azcopy copy "\\fs01\pst-staging" "https://yourstorage.blob.core.windows.net/pst-rollback?<SAS>" --recursive

Troubleshooting

SymptomLikely cause
New-MailboxExportRequest is not recognizedThe Mailbox Import Export role is not assigned, or the shell was not restarted after you assigned it
Export fails with access denied to the shareExchange Trusted Subsystem lacks Read/Write on the share and folder
AzCopy reports an authorization errorThe SAS URL was truncated, not quoted, or & and % were not escaped in a batch file
Mapping file validation fails for a PSTThe name or FilePath does not match the uploaded file's case, or the file is not in the container
Import fails for one user onlyTheir archive is not enabled, the address does not match a mailbox, or two mailboxes share the address (use the GUID)
Imported mail seems to vanish after a few weeksRetention hold was lifted and a retention policy processed the old mail. Adjust the policy first
Folder names look garbled for ANSI PSTsA ContentCodePage value is needed for double-byte languages
Some items are missingItems over 150 MB are skipped. Compare the item counts to the export statistics
Storage Explorer will not connect the second timeThe container was not detached after the last session
The import takes much longer than expectedSeveral large PSTs target the same mailbox and run in sequence. Spread them across mailboxes where possible

The Complete Checklist

If you want help planning a mailbox migration, scoping a hybrid project, or recovering history from an old Exchange server, get in touch.

Exchange Server Azure Blob Storage PST Import AzCopy Microsoft Purview Microsoft 365 Migration New-MailboxExportRequest