The classic Monday morning scenario
You just finished an IMAP migration to Exchange Online. The batch completed without errors in the Exchange Admin Center, mailboxes are synced, users can log in. You close your laptop Friday evening with that satisfying sense of a job done.
Monday morning, the tickets start rolling in. "All my emails are dated Friday." "My inbox history is unusable." "Old emails are missing." Nothing is actually missing: the emails are all there, but Outlook is displaying them with the migration date instead of their original sent date. An email from 2019 shows up dated last Friday. The result: the entire mailbox appears to contain only recent messages.
This is one of the most frustrating problems with IMAP migrations to Exchange Online, and it's almost systematically under-documented by Microsoft.
Why EAC migration breaks dates
When you use the Exchange Admin Center to configure an IMAP migration from an on-premises server (Dovecot, Courier, Cyrus, UW-IMAP, whatever you're running), Exchange Online connects to your source server via IMAP, pulls the messages, and injects them into destination mailboxes through its own internal transport pipeline.
That's where the problem gets created.
Every email that passes through the Exchange transport pipeline automatically receives a timestamped Received: header. This is standard behavior for SMTP and IMAP servers, going back decades: every server that touches a message appends its own timestamp. The problem is that Outlook (especially Outlook for Windows in recent versions) uses the most recent Received: header as its display reference when other metadata is ambiguous.
The original Date: header (the one that shows when the email was actually sent, per RFC 2822) is still in the message. It hasn't been removed. But it gets "eclipsed" by that new Received: header that Exchange added during injection.
At the same time, the IMAP INTERNALDATE (the metadata that IMAP servers use to date messages internally, and which drives sorting in most clients) gets set to the injection date, not the email's original date. Exchange Online has no native way to preserve the source server's INTERNALDATE during a batch migration through the EAC.
EAC vs. third-party tools: an important difference
Two situations are worth separating here. With tools like BitTitan MigrationWiz or CloudM Migrate, the same problem exists, but these tools sometimes include configuration options (partially documented, often buried in advanced settings) that attempt to preserve certain date metadata.
The native EAC migration offers nothing of the sort. Microsoft exposes no parameter to control INTERNALDATE preservation in the batch migration pipeline. It's a black box: you configure the batch, you run it, Exchange does what it wants internally. And what it does, consistently, is date messages to whenever they were injected.
(If you've ever tried reading the raw headers of an email migrated through the EAC, you know the Received: header added by Exchange is instantly recognizable: it contains references to internal Microsoft servers like *.protection.outlook.com or *.prod.exchangelabs.com, with a timestamp that lines up exactly with your migration window.)
Why recreating the batch fixes nothing
The instinctive reaction for many IT admins is: "If I delete the migrated mailboxes and rerun the batch from scratch, maybe the dates will be correct this time."
It's understandable. But it doesn't work.
The problem isn't in the batch configuration. It's not a checkbox you missed. It's in the architecture of the Exchange transport pipeline itself, which behaves identically on every migration. Running the batch again produces exactly the same result: the same Received: headers with the new migration date, and the same incorrect INTERNALDATEs. You'll have wasted time and disrupted users a second time for nothing.
Some admins also try tweaking the sort settings in Outlook ("sort by sent date" instead of "received date"). Sorting by sent date isn't a fix. It's a bandage. The Date: header and INTERNALDATE remain wrong for clients that don't expose this setting, for OWA, for Outlook Mobile, and for any third-party application accessing the mailbox via IMAP or EWS.
What's actually happening in the headers
Here's a simplified example of what an email looks like after migration through the EAC. The original header:
Date: Thu, 14 Mar 2019 09:23:11 +0100
From: alice@olddomain.com
Subject: Q1 2019 Report
After migration, the message gets something like this prepended to its header chain:
Received: from DB7PR0101MB3304.eurprd01.prod.exchangelabs.com
by DB7PR0101MB3305.eurprd01.prod.exchangelabs.com
with HTTPS; Fri, 7 Jun 2024 22:41:03 +0000
Outlook sees this Received: header first (it's added at the top of the header block), interprets it as the most recent processing date, and displays it as the received date. The original Date: header from 2019 is still there, intact, a few lines down. But Outlook doesn't use it for display in the message list.
To be precise: the behavior varies slightly across Outlook versions. Post-2021 versions (and especially the new Outlook for Windows rolled out since late 2023) are particularly sensitive to this because they rely more heavily on Exchange Graph metadata than on the raw Date: header. That means migrations that caused no visible issue with Outlook 2016 can now break with the new Outlook.
Who's actually affected
The most common IMAP source servers in this type of migration are Dovecot (widespread in Linux/cPanel environments) and Courier. Both expose INTERNALDATE values via IMAP that the EAC doesn't preserve. If you're migrating from on-premises Exchange to Exchange Online (hybrid or cutover), the behavior is different because Microsoft uses an internal transport protocol (MAPI/EWS) that preserves metadata better. It's the generic IMAP migration through the EAC that causes the problem.
The hardest-hit users are those with long mailbox histories (5+ years) and high message volumes. A user with 300 emails will recover quickly. A sales director with 12,000 emails sorted by date, who relies on them daily to find client threads, is effectively paralyzed.
Why a homemade script is a bad idea here
Some IT admins who understand the technical problem are tempted to write a PowerShell or Python script to fix the headers manually. The basic concept can seem straightforward once you've identified the mechanism. But actually running a correction in production is a different matter entirely.
First, the edge cases. S/MIME-signed emails and PGP-encrypted messages have a structure that can't tolerate header modification without invalidating the signature. Multipart/alternative messages with malformed MIME boundaries (common on older Courier servers) can be corrupted by a script that modifies the message without correctly reconstructing the structure. Non-ASCII headers encoded per RFC 2047 (sender names with accented characters or Japanese, for example) are a classic source of errors.
Then there's volume. A script that works on 50 test emails in a dev environment doesn't handle Exchange Online API rate limits in production. A 429 Too Many Requests error at 2 AM during a batch of 8,000 messages, with no retry mechanism, means a sleepless night and potentially duplicate or lost messages.
And the bigger question: how do you verify that every corrected email is intact? That no attachment was truncated, no thread broken, that labels and folders are preserved? Without individual validation, you're just hoping everything went fine.
Fixing email dates after migration is a problem that looks like a 50-line script but needs thousands of lines to be reliable in production.
What Redate.io does differently
Redate.io connects to Exchange Online via Microsoft 365 APIs (Azure Active Directory, tenant-level delegation permissions) and scans affected mailboxes to identify emails whose date metadata was corrupted by the migration. This scan step is free and gives an exact picture of the problem's scope: number of affected messages, which mailboxes, the range of corrupted dates.
Redate.io's proprietary correction engine then processes each email individually through a multi-stage analysis pipeline that includes pattern matching against known migration tool signatures (including the Exchange Online transport pipeline), RFC compliance validation, and structural integrity verification before and after correction. S/MIME-signed emails, complex MIME structures, non-standard encodings: all handled through dedicated processing paths.
Every corrected message is verified individually. Originals are kept in a visible backup folder for 30 days. If something looks off with a particular message, it's left alone: Redate.io flags the anomaly rather than risk corruption.
Pricing is volume-based, as a one-time payment per mailbox. No subscription, no recurring fees. You fix the problem once, and it's done.
For Exchange Online migrations specifically, Redate.io supports connection via Azure AD application permissions (without creating individual credentials per mailbox), which makes processing large fleets of mailboxes much simpler to orchestrate for an IT admin or MSP.
If you manage multiple clients who went through this kind of migration, also check out the complete guide on fixing email dates after a Microsoft 365 migration for an overview of the different scenarios covered.
The emails are there, and so are the original dates. Run a free scan on Redate.io to see exactly how many messages are affected across your Exchange Online mailboxes, before deciding what to do next.