Даты писем сломаны после миграции на Exchange Online

7 min

Классический сценарий понедельного утра

Вы только что завершили миграцию IMAP в Exchange Online. Batch завершился без ошибок в центре администрирования Exchange, ящики синхронизированы, пользователи могут войти. В пятницу вечером закрываете ноутбук с чувством выполненного долга.

В понедельник утром начинают сыпаться тикеты. «Все мои письма датированы пятницей». «Папка "Входящие" стала бесполезной». «Куда-то пропали старые письма». На самом деле ничего не пропало: письма на месте, но Outlook показывает их все с датой миграции вместо оригинальной даты отправки. Письмо из 2019 года отображается как полученное в прошлую пятницу. В итоге весь ящик выглядит так, будто содержит только свежие сообщения.

Это один из самых раздражающих сбоев при IMAP-миграции в Exchange Online, и Microsoft его почти нигде толком не документирует.

Почему миграция через EAC ломает даты

Когда Вы используете центр администрирования Exchange (EAC) для настройки IMAP-миграции с локального сервера (Dovecot, Courier, Cyrus, UW-IMAP, не важно), Exchange Online подключается к исходному серверу по IMAP, забирает сообщения и загружает их в целевые ящики через собственный внутренний транспортный конвейер.

Вот здесь и возникает проблема.

Каждое письмо, проходящее через транспортный конвейер Exchange, автоматически получает заголовок Received: с меткой времени. Это стандартное поведение SMTP и IMAP серверов на протяжении десятилетий: каждый сервер, через который проходит сообщение, ставит свой временной штамп. Проблема в том, что Outlook (особенно Outlook для Windows в новых версиях) использует самый последний заголовок Received: в качестве ориентира для отображения даты, когда другие метаданные неоднозначны.

Оригинальный заголовок Date: (тот, что указывает реальное время отправки письма согласно RFC 2822) по-прежнему присутствует в сообщении. Он не удалён. Но он оказывается «в тени» нового заголовка Received:, добавленного Exchange при загрузке.

Параллельно INTERNALDATE по IMAP (метаданные, которые IMAP-серверы используют для внутренней датировки сообщений и которые управляют сортировкой в большинстве клиентов) выставляется на дату загрузки, а не на оригинальную дату письма. Exchange Online не умеет нативно сохранять INTERNALDATE исходного сервера при пакетной миграции через EAC.

EAC против сторонних инструментов: важное различие

Стоит разграничить две ситуации. С такими инструментами, как BitTitan MigrationWiz или CloudM Migrate, проблема тоже существует, но у этих инструментов есть параметры конфигурации (частично документированные, обычно спрятанные в расширенных настройках), которые пытаются сохранять часть метаданных дат.

Нативная миграция через EAC не предлагает ничего подобного. Microsoft не предоставляет никакого параметра для управления сохранением INTERNALDATE в конвейере пакетной миграции. Это чёрный ящик: Вы настраиваете batch, запускаете его, и Exchange сам решает, что делать внутри. А делает он одно и то же всегда: датирует сообщения по времени их загрузки.

(Кстати, если Вы хоть раз смотрели на сырые заголовки письма, мигрированного через EAC, то легко узнаете добавленный Exchange заголовок Received:: он содержит ссылки на внутренние серверы Microsoft типа *.protection.outlook.com или *.prod.exchangelabs.com, с меткой времени, точно совпадающей с окном миграции.)

Почему повторный запуск batch ничего не изменит

Инстинктивная реакция многих IT-администраторов: «А что если удалить мигрированные ящики и запустить batch заново? Может, в этот раз даты будут правильными?»

Понять это желание можно. Но это не работает.

Проблема не в настройке batch. Не в каком-то параметре, который Вы забыли включить. Она в самой архитектуре транспортного конвейера Exchange, который одинаков при каждой миграции. Повторный запуск даст ровно тот же результат: те же заголовки Received: с новой датой миграции и те же неверные INTERNALDATE. Время потеряно, пользователей потревожили второй раз без всякого смысла.

Некоторые администраторы пробуют менять параметры сортировки в Outlook: «сортировать по дате отправки» вместо «даты получения». Сортировка по дате отправки - это не решение. Это пластырь. Заголовок Date: и INTERNALDATE остаются неверными для клиентов, где такой настройки нет, для OWA, для Outlook Mobile и для любого стороннего приложения, обращающегося к ящику через IMAP или EWS.

Что реально происходит в заголовках

Упрощённый пример того, как выглядит письмо после миграции через EAC. Оригинальный заголовок:

Date: Thu, 14 Mar 2019 09:23:11 +0100
From: alice@olddomain.com
Subject: Отчёт Q1 2019

После миграции в начало цепочки заголовков добавляется примерно следующее:

Received: from DB7PR0101MB3304.eurprd01.prod.exchangelabs.com
   by DB7PR0101MB3305.eurprd01.prod.exchangelabs.com
   with HTTPS; Fri, 7 Jun 2024 22:41:03 +0000

Outlook видит этот заголовок Received: первым (он добавляется в начало блока заголовков), интерпретирует его как самую последнюю дату обработки сообщения и показывает как дату получения. Оригинальный заголовок Date: 2019 года по-прежнему там, нетронутый, несколькими строками ниже. Но для отображения в списке сообщений Outlook его не использует.

Если быть точным: поведение немного отличается в зависимости от версии Outlook. Версии после 2021 года (и особенно новый Outlook для Windows, запущенный с конца 2023 года) особенно чувствительны к этой проблеме, потому что они всё больше опираются на метаданные Exchange Graph, а не на сырой заголовок Date:. Это означает, что миграции, которые не вызывали видимых проблем в Outlook 2016, теперь вполне могут ломать даты в новом Outlook.

Кого это реально затрагивает

Самые распространённые исходные IMAP-серверы при таком типе миграции - это Dovecot (очень популярен в Linux/cPanel-средах) и Courier. Оба передают INTERNALDATE через IMAP, который EAC не сохраняет. Если Вы мигрируете с on-premises Exchange на Exchange Online (гибридная миграция или cutover), ситуация другая: Microsoft использует внутренний транспортный протокол (MAPI/EWS), который лучше сохраняет метаданные. Проблема специфична именно для обобщённой IMAP-миграции через EAC.

Сильнее всего страдают пользователи с длинной историей ящика (пять лет и более) и большим объёмом сообщений. Пользователь с 300 письмами справится быстро. А коммерческий директор с 12 000 писем, отсортированных по дате, на которые он опирается каждый день для поиска переписки с клиентами, оказывается полностью парализован.

Почему самописный скрипт здесь не поможет

Некоторые IT-администраторы, разобравшись в технической стороне проблемы, хотят написать PowerShell или Python скрипт для ручной правки заголовков. Базовая идея может показаться простой, когда механизм понятен. Но реальность исправления в production - совсем другое дело.

Во-первых, граничные случаи. Письма с подписью S/MIME и сообщения с шифрованием PGP имеют структуру, которая не терпит изменений заголовков без аннулирования подписи. Сообщения multipart/alternative с некорректными MIME-границами (частые на старых серверах Courier) могут быть повреждены скриптом, который изменяет сообщение без корректной пересборки структуры. Заголовки с не-ASCII-символами, закодированные по RFC 2047 (имена отправителей с кириллицей, японскими знаками и т.д.), - классический источник ошибок.

Во-вторых, объём. Скрипт, который работает на 50 тестовых письмах в dev-среде, не справляется с ограничениями API Exchange Online по частоте запросов в production. Ошибка 429 Too Many Requests в два часа ночи во время batch на 8000 сообщений без механизма возобновления - это бессонная ночь и потенциально дубликаты или потерянные письма.

И главное: как проверить, что каждое исправленное письмо цело? Что ни одно вложение не обрезано, ни одна ветка переписки не сломана, что метки и папки сохранены? Без механизма поштучной валидации остаётся только надеяться, что всё прошло нормально.

Исправление дат после миграции - задача, которая выглядит как 50 строк кода, а на деле требует тысяч строк, чтобы быть надёжной в production.

Как Redate.io решает эту задачу

Redate.io подключается к Exchange Online через API Microsoft 365 (Azure Active Directory, делегированные разрешения на уровне тенанта) и сканирует нужные ящики для выявления писем, у которых метаданные дат были искажены миграцией. Этот этап сканирования бесплатный и даёт точное представление о масштабе проблемы: количество затронутых сообщений, список ящиков, диапазон испорченных дат.

Проприетарный движок коррекции Redate.io затем обрабатывает каждое письмо отдельно через многоступенчатый аналитический конвейер, включающий сопоставление паттернов по сигнатурам известных инструментов миграции (в том числе транспортного конвейера Exchange Online), валидацию соответствия RFC и проверку структурной целостности сообщения до и после исправления. Письма с подписью S/MIME, сложные MIME-структуры, нестандартные кодировки - всё обрабатывается по специальным путям.

Каждое исправленное сообщение проверяется индивидуально. Оригиналы хранятся в видимой резервной папке в течение 30 дней. Если с конкретным сообщением что-то не так, оно не изменяется: Redate.io фиксирует аномалию вместо того, чтобы рисковать повреждением.

Тарификация основана на объёме, разовый платёж за ящик. Никакой подписки, никаких регулярных платежей. Проблема решается один раз - и это всё.

Для миграций в Exchange Online Redate.io поддерживает подключение через разрешения приложения Azure AD (без необходимости создавать отдельные учётные данные для каждого ящика), что значительно упрощает обработку больших парков ящиков для IT-администратора или MSP.

Если Вы обслуживаете нескольких клиентов, которые прошли через подобную миграцию, обратитесь также к полному руководству по исправлению дат после миграции Microsoft 365 для обзора различных сценариев.

Письма на месте, оригинальные даты тоже. Запустите бесплатное сканирование на Redate.io, чтобы узнать точно, сколько сообщений затронуто в Ваших ящиках Exchange Online, прежде чем принимать решение.

Похожие статьи