evgen@spb: ~/2026/07/migracziya-korporativnoj-pochty-s-mail-ru-na-svoj-server/

Как я переносил корпоративную почту с 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_WORKERS2Потоков для закачки. 3–4 заметно ускоряют перенос, но при слишком высоком значении Mail.ru начинает резать соединения.
RECONNECT_ATTEMPTS5Попыток переподключения при обрыве.
RECONNECT_DELAY10Секунд между попытками реконнекта.
FETCH_BATCH_SIZE100Как часто печатать строку прогресса.

По воркерам совет простой: начните с 2, и только убедившись, что переносится стабильно, поднимайте. Выигрыш в скорости от четырёх потоков легко съедается временем на разбор того, почему сервер начал рвать соединения.

Про безопасность

Файл accounts.txt содержит пароли от всех ящиков в открытом виде. Это неизбежное зло при такой задаче, но обращаться с ним надо соответственно: держите его только на доверенной машине и удалите сразу после завершения миграции.

И на всякий случай — в .gitignore:

accounts.txt
*.log

Поверьте, случайно закоммитить файл с корпоративными паролями — это классика, которую лучше исключить заранее.

Итог

Скрипт лежит на GitHub под MIT: mailbox-migration-from-mail.ru. Он написан под конкретную задачу — уход с Mail.ru, — но по сути это обычная IMAP-синхронизация, так что с любым другим IMAP-сервером в качестве источника он тоже отработает: достаточно поменять хост и маппинг папок.

Если пригодится — пользуйтесь. Если найдёте, что улучшить, — пишите.

evgen@spb: ~/contacts
evgen@spbping -c1 evgen.info
64 bytes from evgen.info: отвечу в течение рабочего дня
evgen@spbcat contacts.txt
mail      ya@evgen.info
telegram  @EvgenOne
github    github.com/onegin
blog      evgen.info/blog
evgen@spbecho $ЗАЧЕМ_ПИСАТЬ
интересная инфраструктурная задача · вопрос по Proxmox или Icinga ·
желание обсудить, почему memtest молчал, а память была битая
evgen@spb
© 2026 Евгений Подолинский · Санкт-Петербург
синий здесь – не тот, о котором вы подумали.