Привет, меня зовут Никита, я backend-разработчик в компании ИНТЕРВОЛГА. Работаю в компании уже 3 года, и за этот срок достаточно часто мне приходилось возиться с установкой и конфигурированием собственного почтового сервера для разных задач (см. далее) клиентов.
Сначала это было болью, каждая такая задача требовала понимания проблем каждого клиента, путей их решения, принципов работы почтового сервера и способов его тестирования, чего в начале карьеры у меня не было. В итоге приходилось по крупицам собирать информацию о составных частях поставленной задачи из различных источников.
В этой статье хотелось бы поделиться накопленным опытом, описать возможные трудности и подводные камни, с которыми можно столкнуться в похожих кейсах, и показать некую roadmap решения.
Путь начинается с того, как с нуля, по вводным условиям определить объем работ, и заканчивается финальной реализацией почтового сервера и его тестированием.
Я не видел в Сети и на Хабре цельной инструкции такого рода — и решил написать свою.
Статья не претендует на то, чтобы рассказать про всё сразу и максимально подробно (сомневаюсь, что это реализуемо). Наоборот, я стремился описать сложные и комплексные вещи простым языком. Слишком обширные темы, уже давно разобранные сообществом, я опускал. Главной целью было дать новичку, который закопается в дебрях “почтовых интриг”, указатель, в какую сторону копать при возникновении типовых вопросов и проблем. Надеюсь, что эта статья окажется полезной и найдет своего читателя. Приступим!
Зачем ставить свой почтовик?
Электронная почта стара как мир, и, казалось бы, уже давно наступил момент, когда она должна выйти из моды и уступить место современным способам общения в Сети: разнообразным мессенджерам и социальным сетям. Однако даже сейчас спрос на обмен письмами остается высоким. Коммерческий IT-сектор применяет почту для рекламных рассылок, уведомлений и банального общения с клиентами, и, по моему опыту, не собирается прекращать это делать из-за простоты и доступности этого средства.
По данным Statista.com, в 2022 отправляется более 320 млрд писем каждый день, и это число стабильно растет.
Почтовый механизм разрешает отправлять письма от кого угодно, кому угодно и когда угодно, что разрешает злоумышленникам рассылать рекламный и вирусный спам. Это головная боль, от которой никакими средствами полностью избавиться невозможно. Разработчикам и администраторам приходится применять разные, порой костыльные методы борьбы со спамом: контекстная фильтрация, черные списки, серые списки и прочее – всё это методы, не дающие стопроцентной гарантии защиты от спама, а других попросту не существует. Иногда вводят такие меры настолько агрессивно, что и у порядочных отправителей начинаются проблемы.
Приведу два примера.
Пример 1.
Яндекс, предоставляющий возможность использовать свои почтовые сервисы, с 2021 года стал блокировать отправку писем с подменой отправителя (если вдруг не знали, то да, можно отправить письмо с одного ящика, а отображаться у получателей будет другой). Номинально это было правильное и полезное для защиты пользователей решение, но некоторые CMS используют данную возможность. Например, 1С-Битрикс. Он умеет работать с кастомным почтовым сервером, но маленьким и средним интернет-магазинам при запуске было лень решать вопросы его настройки, и поэтому часть из них выбирали сторонний почтовик от Яндекса. И как только Яндекс перекрыл рубильник подмены заголовков, почта банально перестала отправляться. Клиентам Яндекс.Почты с сайтами на Битриксе пришлось исправлять это в экстренном режиме, с чем я сам неоднократно сталкивался.
Пример 2.
При размещении почтового клиента на выделенном виртуальном сервере, администраторам, как правило, нужно учесть, что большинство провайдеров перекрывают 25 порт в целях безопасности. Это порт, который по умолчанию использует большинство почтовых клиентов для отправки писем. Таким страдают Яндекс в облачных серверах, Amazon и остальные провайдеры, но они позволяют запросить открытие порта. Selectel же, например, заявил, что будет блокировать порт перманентно (пока, правда, этого не произошло). Это добавит еще больше геморроя администраторам при решении этой проблемы.
Правильный выбор и настройка ПО может помочь в решении и профилактике проблем из примеров.
Как работает отправка писем?
Тут краткий ликбез, важный для понимания и осознанности конфигурирования почтового сервера. Мы не будем касаться тонких особенностей работы протокола SMTP, только общей схемы обмена сообщениями между участниками процесса. Мне самому для понимания, какие опции сервера нужно настраивать, а какие не нужно, очень помогало держать в голове такую схему.
Рассмотрим следующий простейший пример:
У пользователя Боба есть почта на Yandex и друг Фил, у которого почта на Mail.ru.
Боб захотел пообщаться с Филом по почте, он со своего компьютера с помощью почтового клиента Outlook отправляет сообщение.
Outlook знает, что письмо нужно передать в почтовый сервер Yandex, передает его, а сервер Yandex принимает его.
Сервер Yandex по домену адреса ящика Фила “phil@mail.ru” понимает, что письмо нужно отправить на сервер Mail.ru, и пересылает письмо на сервер Mail.ru.
Сервер Mail.ru принимает письмо Боба, сохраняет его к себе в папку “Входящие” на почту Фила и ждет.
Фил заходит в Outlook на своем компьютере, и Outlook проверяет, есть ли на сервере Mail.ru, к которому он подключен, новые письма.
Сервер Mail.ru понимает, что Outlook Фила пытается получить новые письма, и отправляет ему запрошенные сообщения, а Outlook их получает и показывает Филу.
Этот пример можно представить в виде следующей схемы:
Все элементы этой цепочки: Outlook Боба, сервер Yandex, сервер Mail.ru и Outlook Фила – участники обмена почтовым сообщением, которых называют агентами.
Все агенты классифицируются на:
Mail User Agent (MUA) — пользовательский почтовый агент, получает письма и отправляет их. Как правило такие агенты именуются почтовыми клиентами.
Mail Delivery Agent (MDA) — агент доставки письма, дает доступ к письму для MUA получателя.
Mail Transfer Agent (MTA) — агент передачи письма, принимает письма и отправляет их на другие MTA или MDA.
Это функциональная классификация элементов в схеме работы обмена почтовыми сообщениями, она не декларирует соответствие элементов и программного обеспечения. То есть принадлежность элемента к какому-либо классу определяется тем и только тем, что он умеет делать и делает в конкретный момент, но не выбранным ПО.
В примере выше можно определить класс каждого агента по исполняемым ими функциям согласно классификации следующим образом:
Представим, что теперь Фил из примера решил отправить ответное письмо Бобу: в таком случае функциональные классы серверов Yandex и Mail.ru поменяются местами, т.к. теперь Mail.ru будет пересылать письмо Боба, а сервер Yandex будет принимать письмо и складывать его во “Входящие”. В этом и заключается изменчивость принадлежности агентов к функциональным классам.
Важно понимать, что один и тот же физический или облачный сервер (в некоторых случаях одно и то же программное обеспечение) может выполнять разные по классификации функции.
Как, например, сервера Yandex и Mail.ru умеют и пересылать письма, и хранить входящие, и обрабатывать запросы клиентов на получение новых писем, но всё это в разные моменты времени. Когда нужно переслать, сервер выполняет функции MTA, когда сохранить входящее или отдать клиенту новое — MDA.
Yandex и Mail.ru умеют так только потому, что разработчики озаботились настройкой серверной инфраструктуры и софта и потратили на это много денег и времени. Чем больше требуется функций почты, тем затратнее будет настройка. Большинству владельцев почты не нужны ни личные “Yandex” и “Mail.ru”, ни лишние затраты, но нужны отдельные возможности почты.
Поэтому важно заранее определить задачи, которые почтовый сервер должен решать, и после этого уже работать над настройкой инфраструктуры, выбором ПО и конфигурированием.
Конфигурирование сервера Postfix
Рассмотрим выполнение базовой технической задачи для живого проекта — рассылка рекламных сообщений (не спама) с сайта интернет-магазина. Для ее решения нет необходимости в приеме писем, только в отправке и пересылке — соответственно, нам нужны функции MUA (только для отправки) и MTA.
Наименее затратным решением будет использование связки из:
стороннего почтового сервера (MTA);
локального почтового клиента (MUA).
Такое решение может не устроить заказчика. Например, если сторонний почтовый сервер не может подменять отправителя, а этого требует сам сайт. В таком случае потребуется найти другие пути для реализации MTA-функций.
Тут на помощь приходит открытый почтовый сервер Postfix, который сразу после установки уже умеет пересылать электронные письма. Это классно — не нужно тратить время на создание велосипеда. Но придется столкнуться с ворохом ожидаемых проблем при использовании этого почтовика без предварительной настройки. Давайте рассмотрим, какие возникнут трудности и как о них заранее позаботиться.
Установка.
Установить Postfix на сервер можно любым доступным способом. Для удобства здесь и далее будем предполагать, что на сервере стоит CentOS 7, и все команды выполняются из-под пользователя root.
yum install postfix
Готово!
Базовая конфигурация.
При установке Postfix создаются конфиг-файлы по умолчанию, они хранятся в директории /etc/postfix. Для корректного решения нашей задачи потребуется скорректировать файл: /etc/postfix/main.cf.
Основные параметры файла конфигурации main.cf:
myhostname – хост почтового сервера,
mydomain – домен почтового сервера, как правило задается как myhostname без первой компоненты,
mydestination – адрес для получения писем,
myorigin – адрес, который будет указан как отправитель при передаче письма,
inet_interfaces – сетевые интерфейсы, по которым может проходить почта,
inet_protocols – протокол поиска MTA получателя.
Параметры myhostname, mydomain используются в других параметрах как переменные, их задавать не обязательно, но желательно - если изменится хост или домен, не придется переназначать другие параметры.
Параметр mydestination для решения нашей задачи по очевидным причинам не требуется, но он может быть полезен в случае, если ответы получателей на письма требуется складывать в едином хранилище. Например, в том же Яндексе.
Параметр inet_interfaces необходимо настроить для ограничения возможных клиентов сервера. Если почтовый сервер и клиент располагаются на одной машине, то достаточно указать localhost, иначе – тот домен, с которого будут приходить инструкции от клиента.
Параметр inet_protocols, как правило, задают в ipv4, игнорируя ipv6 ввиду его ненужности.
Настройка DNS-записей.
Конфигурации по умолчанию сразу хватает для отправки писем, но они с большой вероятностью будут попадать в спам других почтовиков. Для избежания этого потребуется провести конфигурацию доменной панели под ваш почтовый сервер.
DNS-запись – это строка, в которой содержится информация о сервере, полезная другим участникам обмена сообщениями в сети Интернет. Как правило записи состоят из имени, типа, собственно значения и иногда приоритета и времени жизни. С помощью DNS-записей, например, производится привязка ip-адреса сервера к его доменному имени. Управление записями происходит в доменных панелях хостинга.
Большинство почтовиков при получении писем проверяют их Anti-Spam софтом, который в первую очередь оценивает наличие и корректность DNS-записей. При отсутствии или некорректной настройке записей почтовый сервер получателя может со временем добавить ваш ящик в черный список. Такого при рассылке рекламных сообщений лучше избежать. Для решения поставленной задачи требуется четыре таких записи, каждая из которых настраивается в доменной панели.
MX-запись.
MX-запись – это одна из основных записей типа TXT, необходимых для работы почтовых серверов. Она определяет, по какому адресу нужно отправлять письма, чтобы ваш почтовый сервер как получатель смог их принять.
Для решения нашей задачи эта запись не нужна – не собираемся принимать письма. Поэтому без нее почта будет работать, но большинство почтовых AntiSpam-сервисов требует её наличия. Отсутствие MX-записи не воспринимается ими как критичный признак спама. Письма будут приходить получателям, но нет гарантии, что через время из-за отсутствия MX-записи наш почтовый сервер не поместят в черный список. Поэтому желательно эту запись добавить.
Имя | Тип | Значение |
intervolga.ru | MX | mail.intervolga.ru |
Часто регистрируют корпоративный почтовый домен в сторонних почтовых сервисах, но использование ограничивают только приемом писем. Отправка же происходит с помощью собственного почтового сервера, и в таком случае лучше указать MX-запись на сторонний сервер.
Имя | Тип | Значение |
intervolga.ru | MX | mx.yandex.ru |
Так исходящие письма будут отправляться с использованием Postfix, а входящие — приходить напрямую в Yandex.
SPF-запись.
SPF-запись определяет, каким почтовым серверам разрешено отправлять письма с почтового домена, нужна для защиты от отправки писем сторонними серверами под именем вашего домена. Запись определяет безопасность механизма обмена письмами, поэтому её отсутствие или некорректность как правило критично.
На моей памяти был случай, когда отсутствие записи приводило к периодическому появлению почтовика клиента в публичных черных списках и попаданию писем с него в спам.
SPF-запись имеет составное значение, в нем гибко настраиваются различные параметры SPF. Подробно останавливаться на них не буду, просто приведу пример:
Имя | Тип | Значение |
intervolga.ru | TXT | v=spf1 ip4:123.123.123.123 mx -all |
Данная запись разрешит отправлять от имени домена “intervolga.ru” письма с сервера 123.123.123.123 и тем серверам, что указаны в MX-записях, а остальным запрещает.
Запись обратной зоны DNS (rDNS).
Обратная зона — это механизм для определения IP-адреса сервера по домену. С помощью этой записи проверяется, что отправитель совпадает с тем, что назначен в доменной панели, и определяется, на какой сервер нужно отправлять уведомления об ошибках при приеме писем. Отсутствие этой записи не критично для большинства почтовых проверок на спам. Ситуация аналогична MX-записи: гарантий, что проблем не будет, нет, поэтому рекомендуется эту запись указывать.
Имя | Тип | Значение |
44.33.22.11.in-addr.arpa. | PTR | intervolga.ru |
Отмечу, что эта запись иногда прописывается хостерами автоматически. При аренде виртуальной машины в Yandex.Cloud, например, для задания записи нужно обращаться в техническую поддержку.
Важно понимать, что эта запись задается на стороне хостинга, а не в панели провайдера домена.
DKIM-подпись.
DKIM-подпись — очередной механизм защиты писем от подмены. Отсутствие такой записи не критично, и письма будут приходить получателям, однако это не безопасно, поэтому некоторые почтовики будут относиться к таким письмам с подозрением. Некорректность такой записи критично — это признак того, что письмо подделали, с большой вероятностью его забросят в спам или вовсе не примут.
Процесс настройки DKIM-подписи намного сложнее, чем у других записей, требует предварительной конфигурации на стороне сервера специальных утилит. Не буду подробно разбирать процесс настройки DKIM-подписи, т.к. тогда статья разрастется, подробно про это можно почитать тут и тут.
Внешне DNS-запись для DKIM-подписи выглядит вот так:
Имя | Тип | Значение |
<selector>._domainkey | TXT | v=DKIM1; k=rsa; p=<public_key> |
Отправлять с DKIM-подписью можно с помощью phpMailer
Настройка TLS-подключения к серверу.
Отправка писем по TLS-соединению используется для шифрования, аутентификации и проверки целостности содержимого писем при передаче от одного участника обмена к другому.
Смысл такого соединения: никто не вклинится в процесс и не прочитает передаваемое письмо — препятствует сниффингу.
В случае, когда почтовые клиент и сервер находятся на одной машине, TLS-соединение не нужно, но такие условия не всегда возможны. Если клиент работает в VDS, то ставить там же и сервер часто бессмысленно.
MTA-сервера общаются между собой только по 25 порту, а его в VDS блокируют либо открывают только по специальному разрешению. Это препятствует легкому созданию спам-серверов. В итоге ни одно письмо дальше виртуальной машины не отправится.
Для обхода такого ограничения часто выносят сервер на отдельную машину и настраивают клиент на соединение с ним по 587 или 465 порту, Их обычно открывают, так как они предназначаются для TLS-соединений.
Для настройки работы Postfix с использованием TLS-соединений необходимо:
Выпустить ssl-сертификат.
Опять же, существуют подробные статьи по поводу выпуска ssl-сертификатов, объясняющие, зачем они нужны.
Представим, что уже нужные компоненты есть:
/etc/ssl/certs/postfix/fullchain.pem - полная цепочка сертификатов.
/etc/ssl/certs/postfix/privatekey.pem - ключ для сертификатов.
Добавить несколько опций в /etc/postfix/main.cf
По умолчанию postfix не знает ни о каких сертификатах, и поэтому ему о них нужно сообщить. Делается это с помощью опций smtpd_tls_cert_file и smtpd_tls_key_file:
smtpd_tls_cert_file = /etc/ssl/certs/postfix/fullchain.pem
smtpd_tls_key_file = /etc/ssl/certs/postfix/privatekey.pem
Аналогично серверу Postfix нужно сообщить, в каком режиме работать с теми, кто отправляет письмо без TLS-шифрования.
В нашем случае, т.к. сервер будет использоваться только одним почтовым клиентом, который мы настроим на общение по TLS, логично такие соединения не принимать. Сделать это можно с помощью опции smtpd_tls_security_level::
smtpd_tls_security_level = encrypt
Отмечу, что во многих других статьях указывается, что нужно еще задавать следующие опции значениями yes:
- smtpd_use_tls — сообщение клиентам, поддерживается ли на сервере TLS или нет
- smtp_enforce_tls — сообщение клиентам, что поддерживается только TLS
Этого делать не нужно, так как значение, которое мы задали в опции smtpd_tls_security_level, эквивалентно этим двум опциям.
Открыть 465 порт в системе
Чтобы работать с TLS-соединением нужно корректно настроить брандмауэр системы - открыть в нем 465 порт, которым почтовый сервер будет пользоваться:
firewall-cmd --zone = public --add-port = 465 / tcp –permanent
Включить прослушивания 465 порта Postfix-ом
Из коробки Postfix работает и принимает письма для пересылки только по 25 порту. Чтобы он начал воспринимать соединения на 465 порт, нужно в /etc/postfix/master.cf добавить следующую строчку:
465 inet n - n - - smtpd
Перезапустить Postfix
Чтобы все новые опции и настройки применились, Postfix необходимо перезапустить:
systemctl restart postfix
Готово!
Настройка почтового клиента для общения с Postfix
Почтовый сервер будет исполнять функции MTA, но для отправки писем этого недостаточно, нужен еще и клиент – MUA. Он будет отправлять письма на сервер.
В качестве такого выберем консольный клиент msmtp. Он разработан с приятными для нас достоинствами: бесплатен, прост в конфигурации и совместим с синтаксисом sendmail – базовым почтовым клиентом, который используется в PHP для отправки писем.
Это значит, что msmtp подходит для легкой интеграции с web-сервером.
Конфигурация msmtp.
Конфигурация для почтового клиента задается в файле /home/<user>/.msmtprc конкретного пользователя. Опишу основные интересующие нас опции:
account <account_name> – имя аккаунта, по которому можно производить отправку писем, для аккаунта по умолчанию нужно указать account_name = default.
logfile <logfile_path> – путь до файла с логами клиента.
host <host> - хост почтового сервера, если клиент и сервер расположены на одной машине, то можно указать 127.0.0.1 в качестве хоста.
port <port_number> – порт подключения к почтовому серверу, в нашем случае это 465 порт.
from <default_from_email> – адрес почты, которая по умолчанию будет использоваться в качестве фактического отправителя (если нужно).
auth [on, off] – флаг, использовать или нет авторизацию, в нашем случае значение off.
tls [on, off] – флаг, подключаться ли по TLS-соединению или нет, в нашем случае значени on.
Итоговое содержимое файла /home/<user>/.msmtprc:
account default
logfile <logfile_path>
host <host>
port 465
from <default_from_email>
auth off
tls on
Устанавливается msmtp следующей командой:
yum install msmtp
После этого можно тестировать отправку писем с помощью msmtp:
echo "Test message." | msmtp -a default username@domain.com
Конфигурирование PHP под использование msmtp.
Для использования клиента msmtp в PHP на сайте необходимо поменять в конфигурации языка опцию sendmail_path, указав в ней команду для отправки письма через msmtp. Для этого в /etc/php.ini добавим следующую строку:
sendmail_path = msmtp -t
Опция “-t” сообщает msmtp, что всю информацию об отправляемом письме нужно брать из потока ввода - с его помощью PHP отправляет письма.
Для применения опции останется только перезапустить apache на сервере, если он до этого работал:
systemctl restart httpd
Готово!
Проверка корректности конфигурации.
Существует достаточное количество сервисов для проверки писем на спам, как платных, так и бесплатных. Самым лучший, на мой взгляд — это mail-tester.com.
Mail Tester прост в использовании: отправляется тестовое письмо на указанный на главной странице адрес и запускается проверка. В результате письму выставляется оценка от 0 до 10 с подробным описанием, что, за что и почему.
Аналитика, которую предоставляет этот сервис, достаточно подробная, чтобы быть уверенным в надежности или ненадежности конфигурации почтовика. Оцениваются все необходимые параметры, которые анализируют и остальные публичные почтовые сервисы при получении почты.
Единственный недостаток, который имеется у данного сервиса – это малое количество бесплатных попыток: всего 3 в день. Но как правило даже такого количества хватает для диагностики и исправления всех недочетов, выявленных в ходе тестирования.
В идеале необходимо добиться от сервиса оценки 10\10.
Вывод
Когда я впервые столкнулся с похожей задачей по настройке почтового сервера, то потратил на её решение около 12 часов. Примерно 80% этого времени занял поиск и проверка правильности найденных инструкций. А всё потому, что “а вдруг что-то не то сделаю”, “а вдруг в черные списки перманентно закинут”, “а вдруг как сервер для пересылки будут использовать” и прочие страхи.
Теперь, когда с проблемой знаком и понимаю её, на такую задачу может уйти меньше часа. Надеюсь, что новичкам, кто попадет в такую же ситуацию, моя статья объяснит некоторые неочевидные моменты и придаст уверенности в первых шагах.
Совет 1: проверяйте свой домен/сервер на попадание в черные списки.
Совет 2: следите за тем, что о вас думают крупные email-сервисы: Google, MailRu. К сожалению, Яндекс свой закрыл.
Это мой первый опыт в написании статей, поэтому буду очень рад и благодарен любой критике. Если статья зайдет сообществу, то в будущем разберу более сложные кейсы: клиент и сервер на разных серверах, прием почты, хранение писем в БД и прочее. Задавайте интересующие вопросы, постараюсь на них ответить!