To bulk-import PST files into Exchange Online, create an import job in the Microsoft Purview portal under Data lifecycle management > Microsoft 365 > Import, copy the network upload SAS URL it gives you, and upload the PST files with azcopy.exe copy "<source folder>" "<SAS URL>". You then submit a CSV mapping file that tells the Import service which mailbox (primary or archive) each PST goes to, let the service analyze the data, optionally filter it, and start the import. Network upload is free, needs no Azure subscription of your own, and imports each PST-to-mailbox pair in parallel.
Who this is for and what you will have at the end
This guide is for Microsoft 365 and Exchange Online administrators who need to load a set of PST files into user mailboxes: archived mail from file shares, exports from a legacy system, or PSTs collected from departing users. It covers the network upload method only. If your source is a live mail system, a mailbox migration is usually the better tool; the Google Workspace to Microsoft 365 migration guide covers that path.
By the end you will have:
- A role group that can create import jobs without using Global Administrator.
- Your PST files uploaded to the Microsoft-provided Azure Storage location for your tenant.
- A validated mapping CSV and a running import job.
- A plan for the retention hold that the Import service turns on after the import.
How network upload works and what limits apply
Network upload copies your PST files to a temporary Azure blob container named ingestiondata in the same regional datacenter as your tenant. The Microsoft 365 Import service then reads the files from that container and writes the content into the target mailboxes. You never get a storage account of your own; access is through a Shared Access Signature (SAS) URL that is unique to your organization.
The limits that matter when you plan the batches:
| Item | Limit or behavior |
|---|---|
| Upload tool | AzCopy only. Azure Storage Explorer can list files but can't upload or modify them. |
| PST file size | Upload files no larger than 20 GB; larger files can affect import performance. |
| File names | Each PST file must have a unique name. |
| Mapping file | Maximum 500 rows. Use several mapping files and jobs for more PSTs. |
| Item size | Items larger than 150 MB are skipped. |
| Folder depth | PST files with 300 or more levels of nested folders can't be imported. |
| Archive target | Only the main archive is filled, up to 100 GB per import. Auto-expanding archive storage isn't targeted. |
| Import rate | About 24 GB per day per mailbox. Not guaranteed. |
| Parallelism | Different PST/mailbox pairs import in parallel; several PSTs to the same mailbox import one at a time. |
| Retention of uploads | Files are deleted 30 days after the most recent import job was created, if no jobs are in progress. |
| PST format | ANSI and Unicode, from Outlook 2007 and later. |
| Targets not supported | Public folders and Microsoft 365 groups. |
Two of these shape the whole project. The 20 GB guidance means you should split very large PSTs before upload. The 100 GB archive limit means that if a user's archive needs more than that, you split the data across several imports and leave time for the archive to auto-expand between them.
Prerequisites
Assign the import roles
To create import jobs you need the Mailbox Import Export role and the Mail Recipients role in Exchange Online, or the Global Administrator role. No role group has Mailbox Import Export assigned by default. Microsoft recommends the least-privileged option, so create a dedicated role group in Exchange Online PowerShell:
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName admin@contoso.com
New-RoleGroup -Name "PST Import" -Roles "Mailbox Import Export", "Mail Recipients" -Members admin@contoso.comWithout these roles you can't open the Import page in the Purview portal.
Prepare the source and the target mailboxes
- Put the PST files in a file share, on a file server, or in an Azure Storage location that your organization manages. AzCopy uploads every PST in the source folder, so stage only the files for this batch.
- Rename files so every name is unique, and note the exact case of each name. The mapping file is case-sensitive.
- If you will set
IsArchivetoTRUE, enable the archive mailbox for those users first. If the archive isn't enabled, the import for that user fails (other users in the job aren't affected). - For an inactive mailbox, collect its
ExchangeGuid, because the mapping file needs the GUID instead of the email address:
Get-Mailbox annb@contoso.com -InactiveMailboxOnly | Format-List ExchangeGuidWhen an active mailbox and a soft-deleted or inactive mailbox share the same address, use the GUID to identify the target uniquely. For active mailboxes use Get-Mailbox <identity> | Format-List ExchangeGuid, and for soft-deleted mailboxes add -SoftDeletedMailbox.
Step 1: Copy the SAS URL and download AzCopy
- Sign in to the Microsoft Purview portal at
https://purview.microsoft.comwith an account that has the import roles. - Go to Data lifecycle management > Microsoft 365 > Import.
- On the Import tab, select New import job.
- Enter a job name using lowercase letters, numbers, hyphens and underscores only. Uppercase letters and spaces aren't allowed. Select Next.
- On Do you want to upload or ship data?, select Upload your data, then Next.
- On the Import data page, select Show network upload SAS URL, then Copy to clipboard, and save the URL somewhere protected.
- Select Download Azure AzCopy. This is a standalone executable with nothing to install.
Treat the SAS URL like a password. It grants write access to your organization's upload container. Microsoft supports only the AzCopy version linked from this page (also available at https://aka.ms/downloadazcopylatest) with the documented syntax.
You only do this step once. For later batches, reuse the SAS URL and start again at Step 2.
Step 2: Upload the PST files with AzCopy
Open a Command Prompt, change to the folder that holds azcopy.exe, and run:
azcopy.exe copy "\\FILESERVER01\PSTs" "https://<account>.blob.core.windows.net/ingestiondata?<SAS token>"Rules for the command:
- The source must be a directory or an Azure Storage location, not a single PST file. Every PST in the source is uploaded.
- Surround both the source and the SAS URL with double quotation marks.
--recursiveuploads PSTs in subfolders too. Files in subfolders end up with a different path in the container, and you must use that exact path in the mapping file.- If the source is a general-purpose v2 storage account that supports access tiers, add
--s2s-preserve-access-tier=false. - If you put the SAS URL in a batch file, escape
%as%%and&as^&.
To keep batches apart, add a subfolder after ingestiondata in the destination URL:
azcopy.exe copy "\\FILESERVER01\PSTs\Finance" "https://<account>.blob.core.windows.net/ingestiondata/Finance?<SAS token>"Status messages show progress, and a final message reports the number of files uploaded. Save the working command line in the same protected place as the SAS URL so the next batch only needs a new source path.
Optional: check the upload with Azure Storage Explorer
Azure Storage Explorer helps you confirm the exact names and paths before you build the CSV. In the Connect to Azure Storage dialog, choose Blob container, then Shared access signature (SAS), and paste the SAS URL under Blob container SAS URL. The display name fills in as ingestiondata. When you finish, right-click ingestiondata and select Detach; otherwise the next attach attempt fails. You can't delete uploaded files from here, and an attempt returns a permissions error.
Step 3: Build the mapping CSV
Download the PST Import mapping file template from the Import documentation and keep its header row exactly as it is, including the SharePoint columns the Import service ignores:
Workload,FilePath,Name,Mailbox,IsArchive,TargetRootFolder,ContentCodePage,SPFileContainer,SPManifestContainer,SPSiteUrl
Exchange,,annb.pst,annb@contoso.com,FALSE,/,,,,
Exchange,,annb_archive.pst,annb@contoso.com,TRUE,,,,,
Exchange,Finance,donh.pst,donh@contoso.com,FALSE,/ImportedPst,,,,| Column | What to put in it |
|---|---|
| Workload | Exchange for mailbox imports. |
| FilePath | Blank if you uploaded to the container root; otherwise the subfolder name, such as Finance. Never include ingestiondata. Case-sensitive. |
| Name | The PST file name exactly as uploaded, including case. Must be unique within the job. |
| Mailbox | The target's email address, or the ExchangeGuid for inactive or ambiguous mailboxes. |
| IsArchive | FALSE or blank for the primary mailbox, TRUE for the archive. |
| TargetRootFolder | Blank creates a folder named Imported at the root. / merges into the existing folder structure (Inbox into Inbox). /FolderName imports under that folder. |
| ContentCodePage | Optional code page for ANSI PSTs from double-byte languages, for example 932 for Japanese. |
| SPFileContainer, SPManifestContainer, SPSiteUrl | Leave blank. |
The choice of TargetRootFolder matters for duplicates. The Import service stamps each imported item with the PST item's EntryId and skips items it has already imported, but only within the same target folder. Reimporting the same PST to a different TargetRootFolder imports everything again, and items that already exist natively in the mailbox can be duplicated on first import. Run a small test batch before you settle on a value.
For a user whose primary mailbox is still on-premises in a hybrid deployment, you can import into the cloud archive by setting IsArchive to TRUE and using the on-premises mailbox address.
Step 4: Create the import job
- In Data lifecycle management > Microsoft 365 > Import, select New import job, name it, and choose Upload your data.
- On the Import data page, select I'm done uploading my files and I have access to the mapping file, then Next.
- Select Select mapping file, choose your CSV, and select Validate. The file name turns green when it passes. If it fails, select View log for a per-row error report.
- Accept the terms and conditions, select Save, then Close.
The job appears with the status Analysis in progress. Select Refresh until it changes to Analysis completed.
Step 5: Filter the data and start the import
Select the job and choose Import to Microsoft 365. The Filter your data page shows what the analysis found, including the age of the items.
- No, I want to import everything: select Next, then Import data.
- Yes, I want to filter it before importing: select Next, then More filtering options to set:
- Age: import only items newer than the selected age. Age buckets come from the year of each item's sent or received date.
- Type: clear message types you don't want. The Other category (journal entries, faxes, out-of-office templates, recall reports and similar) can't be excluded.
- Users: exclude messages where specific SMTP addresses appear in the From, To or Cc fields. The data insights don't reflect this filter, but it's applied during the import.
Select Apply, review the summary, and select Import data. When every PST has finished, the job status is Complete.
Verification
- Open the job in the Import list. The status flyout shows the status of each PST file in the mapping file and any filter settings.
- Check that the target folder exists in the user's mailbox or archive and that item counts look reasonable. Message metadata such as sent and received dates and recipients is preserved.
- Check the receive size limit. If a PST contained an item larger than 35 MB, the Import service raises
MaxReceiveSizeon that mailbox to 150 MB:
Get-Mailbox annb@contoso.com | Format-List MaxReceiveSize, RetentionHoldEnabledHandle the retention hold
After an import, the Import service sets RetentionHoldEnabled to True on the mailbox for an indefinite period. The Managed Folder Assistant then doesn't expire or archive items in the user-visible folders, which protects old imported mail from a deletion or archive policy that would otherwise act on it immediately. Items in the Recoverable Items folder are still processed.
Decide how to end it. Either turn it off when users have had time to sort their mail:
Set-Mailbox annb@contoso.com -RetentionHoldEnabled $falseor leave it on and set an end date:
Set-Mailbox annb@contoso.com -EndDateForRetentionHold 12/31/2026The date uses the short date format from the Regional Options of the computer running the command (the example assumes MM/dd/yyyy). RetentionHoldEnabled stays True after that date, but MRM starts processing the mailbox normally, so don't use the property alone to judge whether a hold is still in effect.
A third option is to lengthen the retention age in the policy assigned to the mailbox first and then remove the hold. To list every mailbox still on retention hold:
Get-Mailbox -ResultSize Unlimited | Where-Object {$_.RetentionHoldEnabled -eq $true} |
Format-Table Name, RetentionPolicy, RetentionHoldEnabled -AutoSizeIf imported mail later pushes users toward their quotas, the Recoverable Items folder full guide explains how holds and retention interact with mailbox storage.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Mapping file fails validation | More than 500 rows, a changed header row, or a malformed value | Read View log, keep the template header, split into several CSVs and jobs. |
| A PST fails while others succeed | Name or FilePath case doesn't match the uploaded file | Copy names and paths from Storage Explorer and match case exactly. |
| Archive import fails for one user | IsArchive is TRUE but the archive isn't enabled | Enable the archive and create a new job for that PST. |
| A user needs more than 100 GB imported to the archive | A single import fills only the main archive, up to 100 GB | Split the data across several imports and allow time for auto-expansion between them. |
| File list for an old job is empty | Uploads are deleted 30 days after the last job was created | Upload again and create a new job within 30 days. |
| Large items missing after import | Items over 150 MB are skipped | Expected; the Exchange Online message size limit applies. |
| Duplicate items after reimport | Different TargetRootFolder, or native items without the import stamp | Reimport only to the same target folder; test first. |
| Error on the next Storage Explorer attach | Previous session wasn't detached | Detach ingestiondata after each use. |
| Problems creating a job in the portal | Known issue at 1366 x 768 screen resolution | Change the screen resolution and create the job again. |
Checklist
- Create a role group with Mailbox Import Export and Mail Recipients.
- Stage PSTs under 20 GB with unique names; enable archives where needed.
- Copy and protect the SAS URL; download the supported AzCopy build.
- Upload a directory with
azcopy.exe copy, using a subfolder per batch. - Build the mapping CSV with exact case, at most 500 rows, and a tested
TargetRootFolder. - Create the job within 30 days of upload, validate, filter if needed, and start it.
- Verify per-PST status, then remove or schedule the end of the retention hold.