В качестве предисловия причины всего этого движа
Техничка начнется только в следующем блоке, поэтому если предыстория не интересна – смело пролистывай.
Яндекс 360 — это уже третья (на моей памяти) реинкарнация одного и того же сервиса для хостинга почты и DNS для собственных доменов. Изначально я начал пользоваться этим функционалом в 2013 году и тогда он назывался Яндекс ПДД (почта для домена) и имел незатейливый интерфейс. Главное он работал, работал качественно и был бесплатен. Далее в 2017 он переименовался в Яндекс Коннект и переехал на новый домен. Возможно, уже тогда появился платный функционал, но это меня не сильно потревожило, т.к для меня это было не заметно. В 2020 Яндекс выкатил новую замену – Яндекс 360. В тот момент, с точки зрения админа своих почтовых доменов я даже не заметил разницу. Чуть позже началось продвижение платных услуг и чем дальше в лес, тем голоднее комары постепенно их продвижение становилось все более навязчивым и агрессивным.
Вводные по моему использованию ресурсов Яндекса:
За 10 лет у меня накопилось 10 доменов на сервисе.
От 1 до 15 ящиков на каждом домене.
Забегая вперед общий объем почтовых переписок по всем доменам – менее 10Гб.
Летом 2022 я поддался на рекламу и купил на 1 месяц подписку для одного домена, оплатив с р/с ИП. Мне просто хотелось посмотреть на функционал. Сумма подписки напрямую зависит от количества ящиков и что бы сократить размер платежа я удалил бесполезные ящики на этом домене и оставил только 5шт. Всеми пятью ящиками пользовался я один. Заплатил чуть меньше 300р за каждый ящик. Через некоторое время я протестировал функционал Яндекс 360 (видеоконференции, календари и т.п.) и для меня он оказался практически бесполезными. Именно практически бесполезным, т.к. направлен на работу в команде, а я сам с собой могу договориться и без использования сервиса Яндекс 360. Далее я отказался продлевать подписку и думал, что история исчерпана.
В феврале 23 года мне поступил интересный звонок, который перевернул всё в верх дном. Мне позвонил менеджер из Яндекса и рассказал удивительную историю, что с 17 апреля для меня Яндекс 360 превратится в тыкву, если я не буду платить. Главное ограничение – исходящая почта больше не будет отправляться. Я, конечно, уже не помню в точности разговор и рассказываю о нем как мне запомнилось. Во-первых я не уточнил на сколько доменов будут введены санкции, но быстро прикинул в голове цифру около 7-10тыс ежемесячно за все домены, озвучил это менеджеру, и он меня никак не поправил. Исходя из этого я понял, что меня просто разводят на деньги, а т.к. у меня лежал сервер hp360 gen9 дома и у меня никак не доходили руки разместить его в дата-центре, я принял решение, что пора заканчивать с этими облачными сервисами и поднимать свой почтовый сервер.
Информация от Яндекса в справке: https://yandex.ru/support/business/payment/disable-free-version.html
При этом, если зайти на admin.yandex.ru отображается такое уведомление:
Hidden text
![](https://habrastorage.org/getpro/habr/upload_files/81b/f18/576/81bf1857644fb670a9c956d421caa3df.png)
А еще один раз столкнулся с такой ошибкой при подготовке статьи:
Hidden text
![](https://habrastorage.org/getpro/habr/upload_files/c8b/b06/c63/c8bb06c63ebef2538d7ddfc87a80cd0f.png)
Забегая вперед скажу, что Яндекс на самом деле запланировал ввод ограничений только на тот домен, где ранее был платный сервис 360. Это значительно уменьшало ежемесячную сумму и возможно даже 1.5 тыс рублей ежемесячно не стоили всех трудов по размещению сервера и развертыванию собственного решения. Ведь за размещение сервера + cisco asa + подсеть /28 в Tier II я теперь плачу чуть меньше 8тыс рублей ежемесячно. Хотя, говоря по правде, свой сервер в ДЦ это свой сервер в ДЦ и куча возможностей (ведь не только почтовый сервер можно запустить)! Факт введения санкций только в отношении одного домена я узнал значительно позже и теперь это меня мало волнует.
Муки выбора решения
Я не являюсь почтовым админом и последний раз разворачивал свой собственный почтовый сервер на линухе лет 12 назад. Хотелось бесплатное решение из коробки. Смотрел в сторону зимбры и пиратской инсталляции эксченджа. Но главные минусы этих продуктов – это монстрообразные штуки, которые мне не понятно как поддерживать в будущем. Случайно мне попалось упоминание Mailu. Концепция отличная – контейнеры с опенсорс продуктами и всё работает из коробки. Единственное смущало, что проект завис в развитии и последний релиз 1.8 был в середине 21 года. А т.к. я немного знаком с контейнерами и кубером, то этот вариант мне казался более перспективным, нежели зимбра. За то время, пока я решал вопросы с размещением сервера вышел релиз 2.0 и после все сомнения были отброшены.
Развертывание
Из реальных требований под развертывание:
Белый ip адрес (не попавший в спам базы).
PTR запись для вашего ip адреса.
Корректно настроенный DNS для домена (использую bind9 на другой виртуалке)
Linux x64 с возможностью установить docker и docker-compose (использовал oracle linux 9.1).Пара ядер на сервере (выдал 4 для этой виртуалке, но это избыточно).
Пара гигов оперативы (выдал 6Гб для этой виртуалке, но это избыточно, т.к. в памяти выше 1.5-1.6 гигов лежит только кэш).
Более подробная статья по развертыванию тут
Устанавливаем ОС на целевом сервере. На данном этапе я предпочел выделить отдельный раздел для каталога /mailu (размер оценивайте сами, мусора и логов там не будет. Основная нагрузка – почтовые ящики).
Ставим на целевом сервере docker и docker-compose.
Опционально. Для docker-compose я люблю добавлять алиас в .bashrc: alias d='docker-compose'
На целевом сервере, если это не было сделано ранее создаем каталог /mailu и качаем 2 файла, полученные на предыдущем шаге в этот каталог.
После в этом каталоге запускаем d up -d
И устанавливаем пароль на админскую учетную запись docker-compose -p mailu exec admin flask mailu admin admin mydomain.org PASSWORD
Реально на 5 шаге происходит «магия». За 1 запуск nginx сразу получит все сертификаты от letsencrypt. Все сервисы запустятся и сразу же из коробки будет tls для imap, smtp и pop3. Меня это очень впечатлило.
Минусы системы после развертывания
Антивирус: контейнер с антивирусом не может обновить базы, т.к. возможно российские ip адреса заблокированы. Поэтому толку от такого ClamAV нет. Я его остановил. Как решить эту проблему я не нашел, т.к. было не до этого и я не искал. Если кто знает как завернуть траффик одного контейнера в vpn – подскажите в комментариях.
URI Админки: сделал вывод, что указывать в конфигураторе «Postmaster local part» что-то секретное нет никакого смысла. Путь прослеживается сразу из формы авторизации.
Snappymail: В качестве веб морды выбрал snappymail. Если выбрать отображение по 1000 писем на странице, то вообще не работает. Если по 100, то очень долго и притормаживает из-за долгого выполнения php кода.
Есть косяк в интерфейсе админки. Он меня поставил в ступор. После развертывания и добавления домена веб интерфес подсказывает какие необходимо внести записи на DNS сервере. Но при этом нет полей касаемо DKIM.
Hidden text
![Параметры ДНС для только что добавленного домена Параметры ДНС для только что добавленного домена](https://habrastorage.org/getpro/habr/upload_files/07e/e48/7ce/07ee487ce3b41fc3220043a4f950047e.png)
Оказалось, что необходимо нажать кнопку «Сгенерировать ключи», чтобы появились поля для настройки DKIM. Мне кажется это как-то не очевидно. Тем более при нажатии на кнопку выскакивает предложение «Вы собираетесь совершить regenerate keys for habr.com. Подтвердить?». Я раза только с третьего решился перегенерировать ключи, т.к. было лень bind9 переконфигурировать. Результат меня удивил – появились ключи DKIM.
Hidden text
![ДНС параметры домена после перегенерации ключей. ДНС параметры домена после перегенерации ключей.](https://habrastorage.org/getpro/habr/upload_files/c53/9ac/07b/c539ac07b273d416e6fb367fe25761e3.png)
Так же есть проблема с передачей названий каталогов в fetchmail, но только закодированных в модифицированной utf-7 кодировке. Но об этом дальше.
Fetchmail: Собственно основная боль… У меня стояла задача перенести всю почту не потеряв ни единого письма.
Fetchmail ставится отдельным контейнером. Конфигурируется из веб морды основной системы. При этом нет какой-то общей админской части. Т.е. необходимо из под каждой почтовой УЗ настроить сбор писем на удаленном сервере. Так перенести пару-тройку ящиков еще можно, но когда их больше 10 ты будешь страдать.
Собственно, fetchmail в комплекте используется достаточно старый 5-ый релиз. В то время как 6-ой давным-давно вышел. Хотя на результат это никак не влияет. У fetchmail очень мало параметров по забору почты. Либо забирает все непрочитанные и сразу помечает их прочитанными, либо забирает всё без разбора. Из веб морды можно настроить только 2 варианта: забираем непрочитанные и помечаем их прочитанными либо забираем всё и всё удаляем. Задание в планировщике по умолчанию выполняется раз в 10 минут.
Тут начались костыли с тем, что бы забрать всё, не перепомечая ручками все письма в ящике непрочитанными. Пришлось вытащить питоновский скрипт, запускающий fetechmail и крутить его в руках, что бы вмешиваться в передаваемые параметры. Благодаря этому удалось всё забрать из каталога INBOX и положить на собственный сервер, не удаляя на яндексе. Пришел черед экспериментов с такими папками как Черновики и Отправленные. Во-первых оказалось, что если в вебморде вписать несуществующий каталог в почтовом ящике посередине списка существующих каталогов, то процесс оборвётся на несуществующем каталоге. Во-вторых я узнал о существовании модифицированного utf-7 для обозначения кириллических каталогов. Вот так выглядят реальные имена каталогов:
Нежелательная почта | &BB0ENQQ2BDUEOwQwBEIENQQ7BEwEPQQwBE8- &BD8EPgRHBEIEMA- |
Отправленные | &BB4EQgQ,BEAEMAQyBDsENQQ9BD0ESwQ1- |
Исходящие | &BBgEQQRFBD4ENARPBEkEOAQ1- |
Черновики | &BCcENQRABD0EPgQyBDgEOgQ4- |
Шаблоны | &BCgEMAQxBDsEPgQ9BEs- |
Удаленные | &BCMENAQwBDsENQQ9BD0ESwQ1- |
INBOX | INBOX |
Как видно папка Отправленные в utf-7 содержит запятую и при добавлении через веб интерфейс это имя разбивается на два разных &BB4EQgQ и BEAEMAQyBDsENQQ9BD0ESwQ1-. Идут попытки синхронизации и Яндекс конечно же с радостью сообщает, что каталога &BB4EQgQ нет, а как мы уже знаем, что при несуществующем каталоге синхронизация останавливается.
Я решил, что одним костылём больше или меньше меня не сильно волнует и вкорячил эти папки в тело скрипта, который в контейнере. Дело сдвинулось с мертвой точки. Каталоги успешно синхронизировались, я открыл веб и интерфейс на своем сервере и не обнаружил писем в катале Sent… Но при этом я обнаружил все отправленные письма в каталоге INBOX. На этом можно было так всё и оставить, т.к. сам факт есть, что письма перенесены, но кривой результат мне не давал покоя. Я в тот момент понял, что ничего не понимаю в почте и на неделю забросил все эти эксперименты.
Собравшись с силами через неделю, я пошел изучать первопричину такого поведения. Оказалось, что fetchmail направляет письма в dovecot по протоколу lmtp. Среди кучи существующих параметров в fetchmail я не нашел ни одного позволяющего указать каталог при передаче письма в dovecot. Возможно это вообще не возможно.
IMAPSYNC
Далее я начал искать альтернативное решение и набрел на статью на хабре.
Реализация imapsync из этой статьи выглядела рабочей, но без должной упаковки в контекст реализации Mailu. Просто для теста развернул код из статьи локально и попробовал воспроизвести. Оказалось, что для моих целей это подходит.
Основные плюсы реализации:
Проводится синхронизация всех папок. Для теста попробовал синхронизировать вложенную папку INBOX.test123 и все успешно получилось без костылей.
Синхронизация кириллических каталогов производится в английские аналоги (Отправленные -> Sent, Черновики -> Draft и т.п.).
Работает достаточно быстро при передаче сообщений. Примерно 20-70Мбит/с я наблюдал.
Основные минусы реализации:
Без указания корректных учетных записей и паролей никак. Следовательно процесс идет не автоматизировано для всего домена.
Возможны просадки по скорости при получении списка писем. Наблюдал скорость получения списка почты от Яндекса со скоростью 4-8Кбит/с. Следовательно процесс запуска непосредственной синхронизации бывало тупил.
Реализацию из статьи надо где-то запускать отдельно.
В этот момент я понял, что хочу написать статью на хабр, что бы у людей было полное представление о том, что надо делать, если захотят повторить, но писать статью на Хабр, со словами: «Смотрите я нашел статью на Хабре и ей воспользовался – она работает!» ну как-то глупо. В условии, что всё оставшееся запускается в контейнерах, а imapsync надо где-то рядом положить. Поэтому было принято решение реализацию imapsync завернуть в контейнер и дать другим людям возможность быстро запускать в рамках docker compose существующей инсталляции Mailu.
Собрал всё в контейнер. Из интересного – обнаружилось, что в скрипте миграции почтового ящика (startimapsync.sh) мешаются комментарии для запуска цельной команды. Пришлось их убрать. Также в html форму добавил стандартный сервер источник imap.yandex.ru, а в качестве стандартного сервера назначения указал imap (dns имя контейнера dovecot). Так же для сервера назначения данные будут передаваться без шифрации. Если необходимо использовать ssl, то для этого доступен отдельный контейнер с тегом 993-port. Контейнер получился достаточно жирным, почти 170Мб, т.к. содержит кучу зависимостей для утилиты imapsync, апач и php.
Так же надо учитывать, что при попытке повесить imapsync на рандомный порт и пытаться работать с ним по http, то могут возникнуть проблемы из-за HSTS. Каждый раз чистить HSTS кеш в браузере для открытия странички – это боль, поэтому надо использовать nginx.
Для добавления в существующий docker-compose файл контейнера imapsync делаем следующее:
cd /mailu
wget https://raw.githubusercontent.com/vajrock/imapsync/main/docker-compose.patch
patch < docker-compose.patch
wget -P /mailu/overrides/nginx/ https://raw.githubusercontent.com/vajrock/imapsync/main/imapsync.conf
d stop front && d up -d front imapsync --no-deps
После этого можно подключиться к <ваш_домен>/imapsync/ и начать процесс переноса ящиков.
Процесс переноса
Зная логин/пароль к своему почтовому ящику далеко не факт, что вы его сможете сходу синхронизировать.
Во-первых, Яндекс не дает использовать imap для тех ящиков, что не завершили регистрацию через веб интерфейс. После сброса пароля на ящике каждый раз у меня возникала необходимость нажать кнопку в веб интерфейсе после авторизации с новым паролем.
Во-вторых, не у всех пользователей оказалась активна галочка на разрешение подключения по imap со стандартным паролем пользователя. Даже на тех почтовых ящиках, что ранее гарантированно использовались в почтовых клиентах. Также не помогло включить imap для всех ящиков, установив галочку «IMAP» в админке домена.
Поэтому выработался такой порядок:
Сброс пароля для пользователя в админке Яндекса.
Авторизация под пользователем в приватной вкладке.
Подтверждаем регистрацию.
Шестеренка -> Все настройки -> Почтовые программы и включаем галочку «Портальный пароль».
В админке Mailu создаем пользователя.
Переходим в imapsync и запускаем синхронизацию.
Можно выполнить пункты 1-5 для другого ящика пока идет процесс переноса текущего
Проверяем результат и закрываем приватную вкладку.
Послесловие
Эта статья не претендует на звание правильного во всех отношениях руководства к действию. Автор не преследовал цель дискредитировать сервисы Яндекса. За 10 лет успешного пользования сервисами Яндекса у меня не возникало каких-либо критических проблем, а решение было принято попробовать самому реализовать свой почтовый сервер, т.к. нет уверенности, что еще через 10 лет письма со всей исторической перепиской вообще будут доступны (данные на Яндекс Диске у перенесенных пользователей уже были удалены... возможно было уведомление по этому поводу, но я его просто пропустил :( )
У автора с первой четверти первого класса и до окончания школы всегда была твердая тройка по русскому языку, поэтому прошу не пинать на орфографию и т.п. Просто напишите в личку если обнаружили косяк.
Артефакты из статьи:
Докер хаб: https://hub.docker.com/r/vajrock/imapsync
Гитхаб репа: https://github.com/vajrock/imapsync