Monday, October 26, 2026

How to Restore Deleted Emails in Exchange Online (Microsoft 365): The Complete Admin Guide

From the user's own "Recover deleted items" button to PowerShell bulk restores, and how to find out who deleted what, and when.

"My old emails are gone." Every Microsoft 365 admin hears this sooner or later. The good news is that in Exchange Online, a deleted email is rarely gone for good. Before it is permanently purged, it passes through several safety nets, and with the right tools you can bring it back. You can also prove how it disappeared.

This guide walks through the full process:

  1. Understand where deleted emails actually go
  2. Check whether the mail is really deleted (or just hidden or moved)
  3. Find out who deleted it, when, and from which app
  4. Restore it: self-service, then PowerShell for bulk and targeted restores
  5. Prevent it from happening again

1. The lifecycle of a deleted email

Understanding this flow is what turns "it's gone" into "it's recoverable".

Deleted email lifecycle in Exchange Online
Figure 1: Where a deleted email goes in Exchange Online, and the audit operation logged at each step.
StageWho can see itHow long it staysAudit operation
Deleted ItemsThe userUntil emptied, or removed by a retention tagMoveToDeletedItems
Recoverable Items\DeletionsThe user (via "Recover deleted items") and admins14 days by default, configurable up to 30 (RetainDeletedItemsFor)SoftDelete
Recoverable Items\PurgesAdmins onlyRemoved at the end of the retention period, unless the mailbox is on holdHardDelete
Key insight: If the mailbox is on Litigation Hold or covered by a Microsoft Purview retention policy, deleted items can stay recoverable for years, well beyond 14–30 days. Never remove or change a hold until the restore is finished. Removing it can start the purge clock.

2. Confirm the mail is really deleted

A lot of "missing email" reports are not deletions at all. Rule these out first. It takes five minutes.

CheckWhy it matters
Open Outlook on the web (outlook.office.com) and look for the mailIf it's visible on the web, the problem is the desktop client (cache, filters, collapsed date groups), not the server
Clear filters (Unread, Flagged), switch Focused/Other, and expand collapsed "Older" groupsVery common cause of "only recent mail is visible"
Search all folders for a known old messageInbox rules or Sweep may have moved it, not deleted it
Check the Online Archive (In-Place Archive)A "Move to Archive" retention tag silently moves older mail there

Server-side check with PowerShell

The quickest way to see where items actually are is to compare folder item counts and oldest-item dates:

Connect-ExchangeOnline -UserPrincipalName admin@contoso.com
$upn = "user@contoso.com"
# Item count and oldest item per folder (includes Recoverable Items)
Get-MailboxFolderStatistics $upn -IncludeOldestAndNewestItems |
    Where-Object { $_.ItemsInFolder -gt 0 } |
    Select-Object FolderPath, ItemsInFolder, OldestItemReceivedDate |
    Sort-Object ItemsInFolder -Descending | Format-Table -AutoSize
# Archive, retention policy and holds
Get-Mailbox $upn | Select-Object ArchiveStatus, RetentionPolicy, LitigationHoldEnabled, InPlaceHolds, RetainDeletedItemsFor
Sample folder statistics output
Figure 2: The tell-tale signs. The Inbox oldest date is very recent, Deleted Items is empty, and Recoverable Items\Deletions holds years of mail.
How to read it: If the Inbox's oldest date is very recent, Deleted Items is empty, and /Deletions holds a lot of items going back years, the mail was deleted and then Deleted Items was emptied. It is recoverable.
Run the same command again the next day. If the Inbox's oldest date moves forward, something is deleting mail on a rolling schedule (Sweep, a client rule, a retention policy). If it stays fixed, it was a one-time bulk delete.

3. Find out who deleted the mail, and when

Before you restore anything, find the cause. If a phone app or a client-side rule is deleting mail, it will delete the restored mail again.

Option A: Microsoft Purview audit search (portal)

  1. Go to purview.microsoft.com → Audit → Search.
  2. Set the date range (Audit Standard keeps 180 days by default).
  3. In Activities – operation names, enter: MoveToDeletedItems,SoftDelete,HardDelete
  4. Add the affected user and click Search.
  5. Open any record and check ClientInfoString, LogonType, Folder.Path and AffectedItems.
Generic audit search results
Figure 3: A generic audit search. Pairs of "Moved to Deleted Items" followed by "Deleted from Deleted Items" show a delete-then-empty pattern.

Option B: PowerShell summary (per day, folder and app)

The portal shows one event at a time. For a large investigation, this script summarizes the last 180 days by date, folder, client and logon type, keeping only the summary in memory:

$upn = "user@contoso.com"
$summary = @{}
foreach ($day in 0..179) {
    $start = (Get-Date).Date.AddDays(-180 + $day)
    $end   = $start.AddDays(1)
    $sid   = [guid]::NewGuid().ToString()
    do {
        $page = Search-UnifiedAuditLog -StartDate $start -EndDate $end -UserIds $upn `
            -Operations MoveToDeletedItems,SoftDelete,HardDelete `
            -SessionId $sid -SessionCommand ReturnLargeSet -ResultSize 5000
        foreach ($r in $page) {
            $d = $r.AuditData | ConvertFrom-Json
            $client = if ($d.ClientInfoString -match "MacOutlook") { "Outlook-Mac" } elseif ($d.ClientInfoString -match "OWA") { "OWA" } elseif ($d.ClientInfoString -match "iOS|Android") { "Mobile" } else { "Other" }
            $key = "{0}|{1}|{2}|{3}|{4}" -f $start.ToString("yyyy-MM-dd"), $r.Operations, $d.Folder.Path, $client, $d.LogonType
            if ($summary.ContainsKey($key)) {
                $summary[$key] += @($d.AffectedItems).Count
            } else {
                $summary[$key] = @($d.AffectedItems).Count
            }
        }
    } while ($page -and $page.Count -eq 5000)
    Write-Host "$($start.ToString('yyyy-MM-dd')) done"
}
$report = $summary.GetEnumerator() | ForEach-Object {
    $p = $_.Key -split "\|"
    [pscustomobject]@{ Date = $p[0]; Operation = $p[1]; Folder = $p[2]; Client = $p[3]; LogonType = $p[4]; Items = $_.Value }
}
# Biggest delete actions first
$report | Sort-Object Items -Descending | Select-Object -First 25 | Format-Table -AutoSize
FieldWhat it tells you
LogonType0 = mailbox owner, 1 = admin, 2 = delegate
ClientThe app that performed the delete: desktop Outlook, OWA, mobile, or an app using REST/Graph
FolderThe folder the items were deleted from. Filter on \Inbox to separate real mail from alert-folder cleanup.
Spike daysA single day with a huge Items value means a bulk delete. Steady daily counts mean a habit or an automated rule.
Watch out: folder moves by the mailbox owner (the Move operation) are not audited by default. If the audit log shows only a handful of Inbox deletions but the Inbox is empty, the mail may have been moved to another folder first and deleted from there.

4. Restore the emails

Option 1: Self-service in Outlook on the web (small volumes)

  1. Open outlook.office.com and select Deleted Items.
  2. Click Recover items deleted from this folder at the top of the list.
  3. Search or sort by date, select the messages, and click Restore.
Generic recover deleted items dialog
Figure 4: Generic "Recover deleted items" view in Outlook on the web. Restored items go back to their original folder.

This works well for hundreds or a few thousand items. Beyond that, use PowerShell.

Option 2: PowerShell bulk restore (targeted, admin)

Step 1: Grant the role. Get-RecoverableItems and Restore-RecoverableItems are only available with the Mailbox Import Export role, which is not assigned to anyone by default. In the Exchange admin center, go to Roles → Admin roles → Organization Management → Permissions, tick Mailbox Import Export, and save. Or run:

New-ManagementRoleAssignment -Name "MIE-Admin" -Role "Mailbox Import Export" -User "admin@contoso.com"
Tip: Exchange Online only loads cmdlets your roles allow. If you get "The term 'Get-RecoverableItems' is not recognized", the role hasn't taken effect yet. Wait 30–60 minutes, then open a new PowerShell window and reconnect. Confirm with Get-Command Get-RecoverableItems, Restore-RecoverableItems.

Step 2: Restore only what you need. A mailbox's Recoverable Items folder can hold a huge number of items, mostly notification noise. Restoring everything would flood the user's mailbox. Instead, filter by:

  • -LastParentFolderID: the folder the item was deleted from (for example, Inbox only)
  • -FilterStartTime / -FilterEndTime: these match the item's LastModifiedTime, which is roughly when it was deleted
  • -FilterItemType IPM.Note: email messages only

Step 3: Get the Inbox ID in the right format. This is the part most guides skip. Get-MailboxFolderStatistics returns a base64 FolderId, but -LastParentFolderID expects a 44-character hex string (the store GUID plus the folder counter). You can convert one to the other:

$upn = "user@contoso.com"
$inboxFid = (Get-MailboxFolderStatistics $upn -FolderScope Inbox | Select-Object -First 1).FolderId
$bytes    = [Convert]::FromBase64String($inboxFid)
$inboxId  = ($bytes[23..44] | ForEach-Object { $_.ToString("X2") }) -join ""
$inboxId   # 44 hex characters
Sanity check: Every folder in the same mailbox shares the first 32 hex characters (the store GUID). Only the last 12 (the folder counter) differ. Run the same conversion for another folder. If the two IDs share the prefix and have different endings, your conversion is right.

Step 4: Preview first, in small date windows. One query across a large Recoverable Items folder often fails with a server-side timeout. Query one folder and one day at a time, with retries:

$start   = (Get-Date).Date.AddDays(-60)
$end     = Get-Date
$preview = [System.Collections.Generic.List[object]]::new()
foreach ($src in "DeletedItems", "RecoverableItems") {
    $s = $start
    while ($s -lt $end) {
        $e  = $s.AddDays(1)
        $ok = $false
        foreach ($try in 1..3) {
            try {
                $r = Get-RecoverableItems -Identity $upn -SourceFolder $src -FilterItemType IPM.Note `
                    -LastParentFolderID $inboxId -FilterStartTime $s -FilterEndTime $e -ResultSize 1000 -ErrorAction Stop
                if ($r) { $r | ForEach-Object { $preview.Add($_) } }
                $ok = $true
                break
            } catch {
                Start-Sleep -Seconds 20
            }
        }
        if (-not $ok) {
            Write-Host "$src $($s.ToString('yyyy-MM-dd')) FAILED after 3 tries" -ForegroundColor Red
        }
        $s = $e
    }
}
$preview.Count
$preview | Group-Object LastParentFolderID | Select-Object Count, Name   # should be ONE row = $inboxId
$preview | Select-Object Subject, LastModifiedTime | Export-Csv .\restore-preview.csv -NoTypeInformation

Step 5: Restore, using the same windows. Items go back to their original folder:

foreach ($src in "DeletedItems", "RecoverableItems") {
    $s = $start
    while ($s -lt $end) {
        $e = $s.AddDays(1)
        try {
            Restore-RecoverableItems -Identity $upn -SourceFolder $src -FilterItemType IPM.Note `
                -LastParentFolderID $inboxId -FilterStartTime $s -FilterEndTime $e -ResultSize 1000 -NoOutput -ErrorAction Stop
            Write-Host "$src $($s.ToString('yyyy-MM-dd')) restored"
        } catch {
            Write-Host "$src $($s.ToString('yyyy-MM-dd')) FAILED - $($_.Exception.Message)" -ForegroundColor Red
        }
        $s = $e
    }
}

Step 6: Verify.

Get-MailboxFolderStatistics $upn -FolderScope Inbox -IncludeOldestAndNewestItems |
    Select-Object FolderPath, ItemsInFolder, OldestItemReceivedDate -First 1
PowerShell 7 gotcha: If every call fails with "[System.Net.Http.HttpResponseMessage] does not contain a method named 'GetResponseHeader'", that message comes from the module's own error handler. It is hiding the real server error. Update the module (Install-Module ExchangeOnlineManagement -Force), check $Error[0].Exception | Format-List * -Force for the underlying message, and use smaller date windows. If it still fails, run the same commands in Windows PowerShell 5.1.

Option 3: Purview eDiscovery (last resort)

If neither option works, create an eDiscovery search scoped to the mailbox (it includes Recoverable Items), export the results to PST, and import the PST back. It's slower and heavier, but it doesn't depend on the restore cmdlets.

5. Choosing the right method

ScenarioBest method
A few emails, deleted recentlyThe user restores them in Outlook on the web
Thousands of emails, one folder, a known date rangeRestore-RecoverableItems with -LastParentFolderID and date windows
Restore into a separate folder for reviewRestore-RecoverableItems -RestoreTargetFolder "/Recovered" (Exchange Online only)
Past the retention period, no holdNot recoverable from Exchange. Check backups if your organization has a third-party backup.
Legal or compliance export neededPurview eDiscovery search and export

6. Prevent it from happening again

ActionWhy
Set RetainDeletedItemsFor to 30 daysDoubles the default safety window: Set-Mailbox user@contoso.com -RetainDeletedItemsFor 30
Review client-side rules and SweepRules created in desktop or mobile Outlook, and Sweep, may not appear in Get-InboxRule
Disable "Empty Deleted Items on exit" for heavy deletersStops instant emptying of Deleted Items
Route alert and notification email to a dedicated folder or shared mailboxUsers won't mass-delete from the folders where their real mail lives
Enable an Online Archive with a sensible "Move to Archive" tagKeeps the primary mailbox lean, so users don't feel the need to bulk delete
Use a retention policy for critical mailboxesDeleted items stay recoverable for as long as the policy requires

Key takeaways

  • Deleted mail goes Deleted Items → Recoverable Items\Deletions → Purges. With a hold, it stays recoverable much longer.
  • Always investigate before restoring. The audit log tells you who, when, from which folder, and with which app.
  • Restore selectively. Filter by the original folder and date, and preview before you restore.
  • Convert the base64 FolderId to the hex LastParentFolderID to target one folder precisely.
  • Query in small date windows to avoid server-side timeouts on large mailboxes.
  • Don't touch holds until the restore is complete.

References

No comments:

Post a Comment

Featured Post

How to Restore Deleted Emails in Exchange Online (Microsoft 365): The Complete Admin Guide

From the user's own "Recover deleted items" button to PowerShell bulk restores, and how to find out who deleted what, and whe...

Popular posts