Инструмент для переезда почты с одного сервера на другой — imapsync. Он подключается по IMAP к обеим сторонам и переносит содержимое ящика с сохранением структуры папок, дат и флагов прочитанности.

Оговорюсь честно о жанре. У меня в материалах по фактическому переносу ничего не зафиксировано: инструмент был выбран и запланирован, а деталей реальной операции я не записал. Поэтому здесь будет порядок действий и то, что я думаю про планирование такой работы, — но не рассказ о проблемах, которых у меня не было. Придумывать инцидент ради красивой истории смысла нет.

Коротко

  • imapsync ходит по IMAP с обеих сторон, сохраняя папки, даты и флаги.
  • Планировать стоит как операцию в два прохода, а не в один.
  • Время простоя определяется не объёмом почты, а разницей между проходами.

Почему в два прохода, а не в один

Это единственное, что я считаю по-настоящему важным в планировании такого переезда.

Соблазн очевидный: назначить время, остановить старую почту, перелить всё, включить новую. На ста сорока ящиках это означает простой длиной во весь объём переноса — то есть часы, в течение которых почта не работает ни там, ни там.

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

Второй проход — короткий добор в момент переключения. Он переносит только то, что накопилось с первого прохода.

Отсюда простое следствие: время простоя равно не объёму почты, а разнице между двумя проходами. Чем ближе первый проход к моменту переключения, тем короче второй. Это то, чем можно управлять, в отличие от общего объёма.

Как это выглядит на практике

Один ящик:

# пароли — в файлы, а не в командную строку
umask 077
secrets=$(mktemp -d)
trap 'rm -rf "$secrets"' EXIT
printf '%s' 'ПАРОЛЬ_ПРИЛОЖЕНИЯ' > "$secrets/src"
printf '%s' 'ПАРОЛЬ' > "$secrets/dst"

docker run --rm -v "$secrets:/secrets:ro" gilleslamiral/imapsync imapsync \
  --host1 imap.yandex.ru --port1 993 --ssl1 \
  --user1 user@example.com --passfile1 /secrets/src \
  --host2 mail.example.com --port2 993 --ssl2 \
  --user2 user@example.com --passfile2 /secrets/dst \
  --automap --justfolders   # сначала только папки, потом без этого ключа

Пароль, переданный аргументом --password1, виден любому пользователю машины через ps и оседает в истории оболочки — сама документация imapsync честно об этом предупреждает. Поэтому пароль лучше класть в файл с правами только для владельца (umask 077 — до создания файла, не после) и передавать его через --passfile1/--passfile2.

Ключ --justfolders в первом запуске — недорогая страховка. Он переносит только структуру, без содержимого: если в именах папок или в правах что-то не так, вы узнаете об этом за секунды, а не в середине многочасового переноса.

Пакетно, из CSV вида user;pass_yandex;pass_new:

umask 077
secrets=$(mktemp -d)
trap 'rm -rf "$secrets"' EXIT

while IFS=';' read -r u p1 p2; do
  printf '%s' "$p1" > "$secrets/src"
  printf '%s' "$p2" > "$secrets/dst"
  docker run --rm -v "$secrets:/secrets:ro" gilleslamiral/imapsync imapsync \
    --host1 imap.yandex.ru --ssl1 --user1 "$u" --passfile1 /secrets/src \
    --host2 mail.example.com --ssl2 --user2 "$u" --passfile2 /secrets/dst \
    --automap > "log_${u}.txt" 2>&1
done < users.csv

Тот же приём, что и с одним ящиком, только внутри цикла: пароли по каждому ящику по очереди попадают в два файла в каталоге с правами 700, а не передаются аргументом. trap на выход подчищает каталог с паролями, даже если цикл прервётся посреди ста сорока ящиков, — на этом гоняется он часами, и оставлять secrets-каталог на диске до ручной уборки не стоит.

Отдельный лог на каждый ящик — не педантизм. При ста сорока ящиках общий лог превращается в нечитаемое полотно, и вопрос «а у этого человека всё перенеслось» останется без ответа.

CSV с паролями удалить сразу после миграции. Это файл, в котором лежат пароли ко всем ящикам компании сразу — и он имеет обыкновение задерживаться в домашнем каталоге на годы. Удалять надо не «потом», а в тот же день, когда перенос закончен.

В самом mailcow есть Sync jobs — тот же imapsync, но из веб-интерфейса. Для второго, добирающего прохода перед переключением MX это удобнее: задание настраивается один раз и запускается повторно.

Что стоит держать в голове

Доступ по IMAP на обеих сторонах должен быть проверен до дня X. Не «должен работать», а проверен — на реальном ящике, с реальным паролем. Пароли приложений и двухфакторная аутентификация на стороне облака умеют преподносить сюрпризы именно в тот момент, когда проверять уже поздно.

Структура папок переносится как есть — вместе со всеми её особенностями. Если у людей глубокая вложенность и длинные имена, они переедут в точности такими же. Это само по себе не проблема переноса, но может стать проблемой позже, уже на стороне почтовых клиентов. У меня стала — но это отдельная история, и она не про imapsync.

Порядок ящиков имеет значение. Начинать стоит не с директора, а с того, кто готов потерпеть, если что-то пойдёт не так. Первый ящик — это всегда проверка процедуры, а не перенос почты.

Чего здесь нет

Не будет рассказа о том, сколько заняло, что сломалось и как чинилось. Не потому что всё прошло гладко или негладко, а потому что у меня нет записей, а по памяти такие вещи восстанавливаются неточно — и неточность потом живёт в статье как факт.

Если по итогу переноса появится что рассказать по фактам, напишу отдельно.