Checklist
Email never arrived? Using message trace in Exchange Online to find out why
Based on the article: Email never arrived? Using message trace in Exchange Online to find out why · 5 min read
"I never got that email" is a classic helpdesk ticket, and guessing wastes everyone's time. Message trace shows whether Exchange Online received a message, what it did with it and where it ended up. In this post I'll walk through tracing in the Exchange admin center and with the V2 PowerShell cmdlets, how to read the results, and what to do next for each outcome.
Before you start
Traces covering 10 days or less return results almost immediately.
- Permissions: the Exchange Administrator role in Microsoft Entra ID, or membership of the Organization Management role group in Exchange Online.
- Facts from the user: sender, recipient, roughly when it was sent (and in which time zone) and the subject. If anyone has a copy, the
Message-IDfrom the headers is the most precise filter there is. - For PowerShell: the ExchangeOnlineManagement module, version 3.7.0 or later.
Checklist
- 1
Run a trace in the Exchange admin center
- In the Exchange admin center (
admin.exchange.microsoft.com), go to Mail flow › Message trace. The Exchange message trace link in the Microsoft Defender portal opens the same page. - Select Start a trace. The defaults search all senders and recipients for the last two days.
- Enter the Senders and/or Recipients. External addresses work, and so does one wildcard per value, such as
*@fabrikam.com. - Set the Time range. Switch to Custom time range to pick a time zone and exact start and end times.
- Under Detailed search options, narrow it with a subject filter (starts with, ends with or contains), a delivery status, the Message ID (including the angle brackets) or the direction.
+1 more in the full article.
- In the Exchange admin center (
- 2
Read the delivery status
Status What it means Next step Delivered Handed to the mailbox or the recipient's mail server Mail flow worked. Check Junk Email, Inbox rules and the Other tab. Failed Not delivered Open the details; the Fail event carries the reason and NDR code. Pending Delivery is being attempted or retried Look at the Defer events and the To IP; usually a receiving-side problem. Quarantined Held as spam, bulk or phishing Review it on the Quarantine page of the Microsoft Defender portal. Filtered as spam Identified as spam and rejected or blocked, not quarantined Check the verdict in the details and which anti-spam policy applied. Expanded A group was expanded to its members Trace the individual members. Getting status Received moments ago, no data yet Wait a few minutes and refresh. You may also see Recalled when the sender used Message Recall. Two caveats: you can only filter on Pending, Quarantined and Filtered as spam in searches shorter than 10 days, and the reported status can trail reality by five to ten minutes.
- 3
Open the message trace details
Click a row (not its round check box) to open the details. Expand Message events and read them in order:
Receivefirst, then any processing, ending inDeliver,Send,FailorDefer. - 4
Trace from PowerShell with the V2 cmdlets
Get-MessageTraceV2andGet-MessageTraceDetailV2replaceGet-MessageTraceandGet-MessageTraceDetail, which Microsoft is retiring, so update any old scripts. The rules have changed:- Data goes back 90 days, but one query can span at most 10 days. Without dates you get the last 48 hours.
- Results default to 1,000 rows and
-ResultSizegoes up to 5,000.-Pageand-PageSizeare gone. - Timestamps are in UTC, and a tenant can run 100 queries in any five-minute window.
powershellConnect-ExchangeOnline # Failed messages to one recipient in the last 24 hours $trace = Get-MessageTraceV2 -RecipientAddress user@contoso.com -Status Failed ` -StartDate (Get-Date).AddDays(-1) -EndDate (Get-Date) $trace | Format-Table Received, SenderAddress, Subject, Status # Event-by-event detail for the same messages $trace | Get-MessageTraceDetailV2 | Format-List - 5
Go further back with downloadable reports
For ranges longer than 10 days, or when you need more detail, the admin center builds two CSV reports from archived trace data: the Enhanced summary report (adds direction, original client IP and connector) and the Extended report (full routing and event detail). Both need at least a sender, recipient or Message ID.
In PowerShell, the equivalent is a historical search, which covers messages up to 90 days old:
powershellStart-HistoricalSearch -ReportTitle "Partner invoices" -ReportType MessageTraceDetail ` -StartDate (Get-Date).AddDays(-30) -EndDate (Get-Date).AddDays(-12) ` -SenderAddress billing@fabrikam.com -NotifyAddress admin@contoso.com Get-HistoricalSearch | Format-Table ReportTitle, Status, Rows
Verify
- No record at all: the message never reached Exchange Online. Recheck the address spelling, time range and time zone, confirm your MX record and connectors, then ask the sender's admin for their outbound logs.
- Delivered but not visible: look at Junk Email, Inbox rules, Focused Inbox and any auto-delete or retention settings. Message trace can't see what happens after delivery.
- Failed: the NDR code in the Fail event is your starting point.
- Quarantined or Filtered as spam: decide whether it's a false positive, release it if appropriate and submit it to Microsoft for review.
- Pending for hours: the receiving server is deferring. If retries eventually run out, the sender gets an NDR.
Tips & gotchas
- The admin center shows times in the time zone from your Exchange account settings, while PowerShell returns UTC. Mixing the two up is an easy way to search the wrong window.
- For a message sent to more than 1,000 recipients, filter by
-MessageTraceIdto get complete results. - Prefer
-SubjectFilterType StartsWithorEndsWithoverContains; Microsoft recommends them for performance. - Historical searches are capped at 250 per tenant in 24 hours, and cancelled ones still count.