Reference
Message tracking reference
Based on the article: Message tracking on Exchange Server: following an email with Get-MessageTrackingLog · 5 min read
"Did my email arrive?" is the most common mail flow question, and on-premises Exchange answers it with message tracking. Every transport server records what happened to each message it handled. In this post I'll show how to read those records, filter Get-MessageTrackingLog to find the right message fast, search all servers at once, and set location and retention so the history is there when you need it.
How message tracking works
- Each Mailbox and Edge Transport server logs only the events it handled, as CSV files in
%ExchangeInstallPath%TransportRoles\Logs\MessageTracking. Following a message end to end usually means searching several servers. - The file prefix tells you which service wrote the entry:
MSGTRK(Transport service),MSGTRKMS(Mailbox Transport Submission, mail leaving mailboxes),MSGTRKMD(Mailbox Transport Delivery, mail delivered into mailboxes) andMSGTRKMA(moderation approvals and rejections). - Defaults: enabled, 10 MB per file, 1000 MB per log type, 30 days, subject logging on. Circular logging removes the oldest files when the age or size limit is reached. Because the size limit applies per file prefix, a Mailbox server's folder can grow to three times the configured value.
- No message bodies or attachments are logged: you get addresses, subjects, sizes, IDs, connectors and status codes.
- You need a role group that includes the Message Tracking role, such as Organization Management.
The event IDs you'll read
| EventId | What it tells you |
|---|---|
RECEIVE | The message entered transport by SMTP or the Pickup/Replay directory (Source SMTP), or was submitted from a mailbox (Source STOREDRIVER). |
SUBMIT | Mailbox Transport Submission handed the message to the Transport service. |
SEND | Sent by SMTP to the next hop: another Exchange server, a smart host or the internet. |
DELIVER | Delivered to a local mailbox. |
DEFER / FAIL | Delivery delayed and will be retried / delivery failed. |
DSN | A delivery status notification, such as an NDR, was generated. |
EXPAND, RESOLVE, REDIRECT | A distribution group was expanded, a recipient resolved to another address, or mail went to an alternate recipient. |
HAREDIRECT, HARECEIVE | Shadow redundancy copies were created and received; normal with several servers or a DAG. |
AGENTINFO | A transport agent logged its own data, for example a mail flow rule match. |
DROP | Dropped without an NDR, for example a completed moderation request. |
POISONMESSAGE | Moved into or out of the poison message queue. |
A routine message between two mailboxes on one server produces roughly this sequence: NOTIFYMAPI, RECEIVE (STOREDRIVER), SUBMIT, HAREDIRECT, RECEIVE (SMTP), AGENTINFO, SEND (SMTP) and finally DELIVER (STOREDRIVER).
Step-by-step: following one message
1. Start narrow on one server
Get-MessageTrackingLog -Server EX01 -Sender "chris@contoso.com" -Recipients "anna@fabrikam.com" `
-Start (Get-Date).AddHours(-6) -End (Get-Date) -ResultSize Unlimited |
Sort-Object Timestamp |
Format-Table Timestamp, EventId, Source, ConnectorId, RecipientStatus -AutoSizeRelative times such as (Get-Date).AddHours(-6) avoid date-format surprises on servers with a non-US locale. Add -MessageSubject or -EventId to narrow further.
2. Take the MessageId and follow it across every server
The MessageId (the Message-ID header, angle brackets included) stays the same on every hop, while InternalMessageId differs per server. Search all transport servers and record which one logged each entry:
$msgId = "<4867a3d78a50438bad95c0f6d072fca5@ex01.contoso.com>"
Get-TransportService | ForEach-Object {
$server = $_.Name
Get-MessageTrackingLog -Server $server -MessageId $msgId -Start (Get-Date).AddDays(-3) -ResultSize Unlimited |
Select-Object @{n='LoggedOn';e={$server}}, Timestamp, EventId, Source, ClientHostname, ServerHostname, ConnectorId, RecipientStatus
} | Sort-Object Timestamp | Format-Table -AutoSizeEdge Transport servers keep their own logs; if you have them, run the same search on the Edge server.
3. Hunt for failures and delays
Get-MessageTrackingLog -Server EX01 -EventId FAIL -Start (Get-Date).AddDays(-1) -ResultSize Unlimited |
Format-Table Timestamp, Sender, Recipients, RecipientStatus -AutoSize
Get-MessageTrackingLog -Server EX01 -EventId DEFER -Start (Get-Date).AddHours(-4) -ResultSize Unlimited |
Format-Table Timestamp, Sender, Recipients, RecipientStatus -AutoSizeRecipientStatus holds the SMTP status for each recipient, in the same order as Recipients, for example 250 2.1.5 Recipient OK or 550 4.4.7 QUEUE.Expired.
4. Export results for a ticket or spreadsheet
Recipients and RecipientStatus are multi-valued, so join them before exporting, or the CSV shows a type name instead of addresses:
Get-MessageTrackingLog -Server EX01 -Sender "chris@contoso.com" -Start (Get-Date).AddDays(-1) -ResultSize Unlimited |
Select-Object Timestamp, EventId, Source, Sender,
@{n='Recipients';e={$_.Recipients -join ';'}},
@{n='RecipientStatus';e={$_.RecipientStatus -join ';'}},
MessageSubject, MessageId, ConnectorId, TotalBytes |
Export-Csv D:\Reports\tracking-chris.csv -NoTypeInformation5. Prefer a GUI? Use delivery reports
In the Exchange admin center, Mail flow › Delivery reports searches the tracking logs for messages sent or received by one mailbox and presents the result in a readable form. It suits helpdesk staff; under the hood it uses Search-MessageTrackingReport and Get-MessageTrackingReport.
Verify: what "good" looks like
- Internal mail: RECEIVE (STOREDRIVER) and SUBMIT where the sender's mailbox lives, RECEIVE (SMTP) in the Transport service, SEND (SMTP) towards the server hosting the recipient's database, then DELIVER (STOREDRIVER).
- Outbound internet mail: a SEND whose
ConnectorIdis your internet Send connector and whoseServerHostnameorServerIpis the smart host or the recipient's MX. From that point the message is the receiving side's responsibility. - Inbound internet mail: RECEIVE (SMTP) on the Receive connector you expect, then DELIVER.
- Trouble signs: FAIL means delivery failed (look for the matching DSN event); repeated DEFER means Exchange is still retrying, so check
Get-Queue; no entries at all means the message never reached Exchange, so check the sending client or system and the SMTP protocol logs.
Tips & gotchas
- Result limit: without
-ResultSize Unlimitedyou only get the first 1000 entries. Keep the time window tight on busy servers. - UTC in the raw files: the CSV files record UTC. If you parse them directly instead of using the cmdlet, convert the times before comparing them with user reports.
- Retention: 30 days is often too short for investigations. Check and extend it per server, and size the disk for up to three times the directory limit on Mailbox servers:
Get-TransportService | Format-List Name, MessageTrackingLog* Set-TransportService EX01 -MessageTrackingLogMaxAge 90.00:00:00 -MessageTrackingLogMaxDirectorySize 5GB - Privacy: if subjects mustn't be stored, run
Set-TransportService EX01 -MessageTrackingLogSubjectLoggingEnabled $false. - Related addresses: on EXPAND, REDIRECT and RESOLVE events,
RelatedRecipientAddressshows the other address involved, such as the group or the original recipient. - Next steps: once a SEND to Exchange Online appears, continue in Exchange Online message trace. For POISONMESSAGE entries, see the poison and Submission queue guide.