Как я переносил корпоративную почту с Mail.ru на свой сервер
Задача звучала просто: перенести корпоративную почту с Mail.ru / VK WorkSpace на собственный сервер. Ящиков — несколько десятков, в каждом тысячи писем, накопленных за годы. Условие одно: не потерять ничего.
Казалось бы, IMAP — стандартный протокол, должны быть готовые решения. Они есть, но каждое упиралось во что-то своё: одни платные и по количеству ящиков, другие не умеют возобновляться после обрыва, третьи ломаются на кириллических именах папок. А обрывы при переносе гигабайтов почты — это не «если», а «когда».
В итоге написал свой скрипт. Он лежит в открытом доступе: github.com/onegin/mailbox-migration-from-mail.ru.
Что умеет
Требования формировались по ходу дела, из тех самых граблей:
- Инкрементальная синхронизация. При повторном запуске копируются только новые письма, дедупликация по
Message-ID. Это ключевое: можно прервать процесс в любой момент и продолжить. - Параллельная закачка. Несколько потоков одновременно тянут письма с исходного сервера.
- Автореконнект. При обрыве SSL или EOF соединение восстанавливается само, миграция продолжается с того же места.
- Маппинг папок. Переводит имена из Modified UTF-7 (в этой кодировке Mail.ru хранит кириллицу) в нормальные названия на целевом сервере.
- Сохранение метаданных. Флаги писем (прочитано, отвечено, помечено) и внутренние даты переносятся как есть.
- Без зависимостей. Только стандартная библиотека Python 3.7+. Никаких
pip installна боевом сервере.
Формат списка аккаунтов
Все учётки лежат в обычном текстовом файле, по строке на ящик:
почта_на_старом|пароль_старый|почта_на_новом|пароль_новый
Пример:
hr@company.com|OldP@ssw0rd|hr@company.com|NewP@ssw0rd
info@company.com|s3cr3t|info@company.com|newSecret
Разделитель — вертикальная черта, и это осознанный выбор. Запятая не подошла бы: пароли сплошь и рядом содержат запятые, и CSV-парсинг разваливался бы на ровном месте. Строки, начинающиеся с #, считаются комментариями.
Настройка
В начале imap.py — блок конфигурации:
IMAP_SERVER_A = "imap.mail.ru" # хост старого сервера
IMAP_PORT_A = 993 # 993 = SSL, 143 = STARTTLS
IMAP_SSL_A = True
IMAP_SERVER_B = "mail.yourserver.com" # хост нового сервера
IMAP_PORT_B = 993
IMAP_SSL_B = True
ACCOUNTS_FILE = "accounts.txt"
ACCOUNTS_DELIMITER = "|"
PARALLEL_WORKERS = 2 # потоков для закачки с сервера А
FETCH_BATCH_SIZE = 100 # частота вывода прогресса (каждые N писем)
RECONNECT_ATTEMPTS = 5
RECONNECT_DELAY = 10 # секунд между попытками реконнекта
Папки в Modified UTF-7
Отдельная история — имена папок. Mail.ru хранит кириллицу в кодировке Modified UTF-7, и «Отправленные» выглядят в протоколе примерно так: &BB4EQgQ,BEAEMAQyBDsENQQ9BD0ESwQ1-. На своём сервере папки обычно называются стандартно, поэтому нужен маппинг:
FOLDER_MAP = {
"&BB4EQgQ,BEAEMAQyBDsENQQ9BD0ESwQ1-": "Sent", # Отправленные
"&BCcENQRABD0EPgQyBDgEOgQ4-": "Drafts", # Черновики
"&BBoEPgRABDcEOAQ9BDA-": "Trash", # Удалённые
"&BCEEPwQwBDw-": "Junk", # Спам
"&BBoEIwQR-": "Junk", # Спам (альт. имя)
}
Точные имена папок на конкретном сервере проще всего выяснить экспериментально:
python3 - << 'EOF'
import imaplib
imap = imaplib.IMAP4_SSL("imap.mail.ru", 993)
imap.login("user@domain.com", "пароль")
_, folders = imap.list()
for f in folders:
print(f.decode())
imap.logout()
EOF
Если какую-то папку переносить не нужно — например, корзину, — добавляем её в SKIP_FOLDERS:
SKIP_FOLDERS = {"Trash"}
Запуск
python3 imap.py
Аккаунты обрабатываются последовательно, внутри аккаунта папки идут по очереди, а письма внутри папки качаются параллельно.
Вывод выглядит так:
2026-07-01 19:00:01 [INFO] === IMAP Sync Tool ===
2026-07-01 19:00:01 [INFO] Сервер А: imap.mail.ru:993
2026-07-01 19:00:01 [INFO] Сервер Б: mail.yourserver.com:993
2026-07-01 19:00:01 [INFO] Воркеров: 2 | Батч: 100
============================================================
Аккаунт: hr@company.com
============================================================
Найдено папок: 6
Маппинг: [&BB4EQgQ,BEAEMAQyBDsENQQ9BD0ESwQ1-] -> [Sent]
-> [INBOX] Проверяю сервер Б...
-> На Б: 1240, на А: 1356
100/1356 | +98 пропущено:2 ошибок:0
200/1356 | +116 пропущено:84 ошибок:0
INBOX: новых 116, уже было 1240, ошибок 0
Sent: новых 5838, уже было 0, ошибок 0
Итог для hr@company.com: новых 5954, уже было 1240, ошибок 0
Лог дублируется в файл с временной меткой рядом со скриптом.
Перезапуск после обрыва
Вот ради чего затевалась дедупликация: если процесс упал — просто запустите скрипт снова.
python3 imap.py
Он сверится с целевым сервером, пропустит уже перенесённое и продолжит с места остановки. Дублей не будет. На практике это означает, что миграцию можно спокойно гонять хоть в три захода, не боясь получить по два экземпляра каждого письма.
Грабли: пароли приложений в VK WorkSpace
Самая неочевидная часть всей затеи оказалась не технической.
Mail.ru требует пароль приложения для доступа по IMAP, если на аккаунте включена двухфакторная аутентификация. Обычный пароль просто не сработает — и вы получите ошибку авторизации, которая никак не намекает на настоящую причину.
Для массовой миграции есть два пути.
Вариант 1 — отключить 2FA на уровне домена. В панели администратора VK WorkSpace: Безопасность → Парольные политики → отключить требование двухфакторной аутентификации. После этого работают обычные пароли. Быстро, но, очевидно, временно ослабляет защиту — включайте обратно сразу после переноса.
Вариант 2 — войти от имени пользователя и создать пароль приложения. В панели администратора: Пользователи → нужный аккаунт → Войти как пользователь. Дальше в веб-интерфейсе: Настройки → Безопасность → Пароли для внешних приложений → создать пароль. Примерно 30 секунд на аккаунт — при десятке ящиков терпимо, при сотне уже утомительно.
Тонкая настройка
| Параметр | По умолчанию | Описание |
|---|---|---|
PARALLEL_WORKERS | 2 | Потоков для закачки. 3–4 заметно ускоряют перенос, но при слишком высоком значении Mail.ru начинает резать соединения. |
RECONNECT_ATTEMPTS | 5 | Попыток переподключения при обрыве. |
RECONNECT_DELAY | 10 | Секунд между попытками реконнекта. |
FETCH_BATCH_SIZE | 100 | Как часто печатать строку прогресса. |
По воркерам совет простой: начните с 2, и только убедившись, что переносится стабильно, поднимайте. Выигрыш в скорости от четырёх потоков легко съедается временем на разбор того, почему сервер начал рвать соединения.
Про безопасность
Файл accounts.txt содержит пароли от всех ящиков в открытом виде. Это неизбежное зло при такой задаче, но обращаться с ним надо соответственно: держите его только на доверенной машине и удалите сразу после завершения миграции.
И на всякий случай — в .gitignore:
accounts.txt
*.log
Поверьте, случайно закоммитить файл с корпоративными паролями — это классика, которую лучше исключить заранее.
Итог
Скрипт лежит на GitHub под MIT: mailbox-migration-from-mail.ru. Он написан под конкретную задачу — уход с Mail.ru, — но по сути это обычная IMAP-синхронизация, так что с любым другим IMAP-сервером в качестве источника он тоже отработает: достаточно поменять хост и маппинг папок.
Если пригодится — пользуйтесь. Если найдёте, что улучшить, — пишите.