Logo
Englika

Как создать свой почтовый сервер (часть 1)

Как создать свой почтовый сервер (часть 1)

В этой статье я опишу, как я поднял свой почтовый сервер, используя Postfix и Dovecot, добавил антиспам защиту, используя Rspamd, и настроил SPF/DKIM/DMARC, чтобы исходящие письма попадали во входящие, а не в спам. В результате у вас будет свой собственный почтовый сервер, в котором вы можете добавить неограниченное количество доменов и почтовых ящиков.

В предыдущей статье, мы обсуждали как происходит процесс доставки электронных писем. Если вы не знаете, что такое MTA, MDA, MRA и что они делают, прочитайте статью как работает электронная почта перед тем, как двигаться дальше.

В процессе настройки, я решил зафиксировать здесь для себя почему я все сделал именно так, а не иначе. Если у вас есть большой опыт в настройке почтовых серверов и вы знаете как сделать что-то намного лучше, вы можете написать мне об этом на почту, которую можете найти внизу этой страницы.

Процесс настройки почтового сервера сильно зависит от того, для чего он будет использоваться. Мне нужен почтовый сервер, чтобы управлять всеми почтовыми ящиками в различных доменах своих проектов (support@domain.com, и т.д.).

Давайте начнем. В начале нам нужно выбрать Mail Transfer Agent (MTA) и Mail Delivery Agent (MDA).

Выбор агентов

Mail Transfer Agent

По исследованию Security Space, проведенному 1 ноября 2023 года (MTA удалось определить на 432467 серверах), Exim используется на 58.73% почтовых серверах (254000), Postfix – на 34.86% (150774), а на остальные несколько процентов приходится несколько десятков других MTA. Вы можете заметить, что за 2023 год количество пользователей Exim сократилось (60.90% в 2022, 58.73% в 2023), а у Postfix выросло (32.49% в 2022, 34.86% в 2023). Возможно они перешли из Exim в Postfix :) В любом случае Exim используется в 2 раза чаще, чем Posfix, а остальные MTA используются крайне редко, поэтому будем рассматривать только их.

Вот что удалось найти про Exim и Postfix:

  1. У Postfix высокая скорость работы очереди по сравнению с Exim, при этом меньшая нагрузка на CPU.
  2. Конфигурирование Exim более гибкое, чем у Postfix. У Exim есть собственный язык, который позволяет писать скрипты для обработки писем.

Из-за скорости работы и безопасности, я решил использовать Postfix.

Mail Delivery Agent

По исследованию Open Email Survey, проведенному в 2020 году (IMAP сервер удалось определить на 3674586 серверах), наиболее популярным IMAP сервером является Dovecot (76.93%), затем Courier (7.95%). На остальные проценты приходится несколько десятков других IMAP серверов. За 8 лет Dovecot (48.37% в 2012, 76.93% в 2020) стал использоваться гораздо чаще, чем Courier (30.70% в 2012, 9.06% в 2020).

Вот что удалось найти про Dovecot и Courier:

  • Многие отмечают, что Dovecot по сравнению с Courier, использует гораздо меньше операций дискового ввода-вывода за счет наличия высокопроизводительной индексации и кеширования. Говорят, что по количеству операций ввода-вывода они могут отличаться в 10 раз.
  • Dovecot использует меньше RAM и CPU по сравнению с Courier.
  • Dovecot хвалят за шуструю работу на почтовых ящиках с 30 папками по ~8000 писем в каждой и ~200 новых сообщений в день в каждой. В сравнении, Courier был очень медленным.
  • В Dovecot есть Full Text Search для поиска писем, чего нет в Courier.

Есть также Cyrus, но он используется гораздо реже (только на 0.58% серверов по данным исследования). Говорят, он имеет почти ту же производительность (операций ввода/вывода, оба поддерживают FTS для поиска писем, и пр.). Если для вас это важно, вы можете сделать бенчмарк Cyrus-IMAP и Dovecot. Подробнее об этом тут. Cyrus поддерживает синхронизацию данных календаря и контактов, но то же самое можно сделать, используя отдельный пакет вместе с Dovecot, напр, Horde Groupware. Он позволяет пользователям управлять и расшаривать их календари, контакты, задачи, заметки и файлы.

Timo Sirainen, как он сказал, вместо того, чтобы сравнивать возможности IMAP серверов, начал сравнивать их исходный код и ему ничто не понравилось. В результате, он разработал Dovecot, который в настоящее время является самым популярным IMAP сервером по всему миру. Peer Heinlein, автор этой книги с предисловием от Timo Sirainen, сказал: "Начиная с версии 2.x, Dovecot намного превосходит всех остальных кандидатов. Courier больше не имеет права на существование, а Cyrus не намного лучше. Dovecot версии 2.2.x предоставляет возможности, о которых администраторы Cyrus даже не могут и мечтать.". Он упомянул следующие преимущества Dovecot:

  • Скорость быстрее.
  • Возможностей гораздо больше.
  • Конфиг чище и более гибкий.
  • Логи проще читать.
  • Соответствует RFC (Cyrus нет).
  • Имеет качественный код. В 2017 году Mozilla провела аудит безопасности кода Dovecot и заявила, что они были чрезвычайно впечатлены качеством кода Dovecot, написав, что "несмотря на большие усилия и тщательно продуманный подход, тестировщикам Cure53 удалось лишь подтвердить отличную репутацию Dovecot в области безопасности".
  • Базовая конфигурация позволяет сделать множество настроек производительности и улучшений.
  • Формат хранения mdbox предоставляет систему хранения, которая хорошо масштабируется даже для миллионов аккаунтов, а также позволяет использовать более медленные жесткие диски и даже object storage.
  • Позволяет реализовать active/active кластеры без особых усилий.

Из-за множества причин, описанных выше, я решил использовать Dovecot.

Мне кажется, что я прочитал помимо официальных документаций почти все статьи, которые мне удалось найти про настройку почтового сервера, используя Postfix и Dovecot, однако я все равно не понимал, как все работает, или почему что-то иногда не работает. Так было до тех пор, пока я не прочитал две замечательные книги о Postfix и Dovecot. Оказалось, что все довольно просто, как только поймешь основы. Поэтому в начале статьи будет теоретическая часть, которая поможет вам все понять, и после этого будут конфиги. Надеюсь, эта статья поможет вам настроить свой собственный почтовый сервер. Надеюсь, она также поможет мне быстро все вспомнить в будущем (на самом деле именно поэтому я ее пишу).

Postfix

Postfix – это Mail Transfer Agent. Грубо говоря, он принимает входящие и доставляет исходящие электронные письма по протоколу SMTP.

Когда MTA принимает входящие письма, он либо передает их Mail Delivery Agent для дальнейшей доставки пользователю, либо перенаправляет их на одну или несколько других электронных почт, либо перенаправляет их в другой MTA. Postfix может самостоятельно сохранять письма в почтовый ящик, но MUA не может связываться с ним по IMAP/POP3 (MDA [Dovecot] делает это).

Если MTA не может доставить письмо или передать его дальше, то он:

  • Отклоняет (rejects) это письмо, если ошибка произошла во время взаимодействия по SMTP. Например, если получатель не существует.
  • Возвращает (bounces) письмо отправителю, если оно уже было принято. MTA создает новое письмо с ошибкой, напр, когда почтовый ящик пользователя переполнен и отправляет его отправителю.
  • Отправляет письмо администратору.

Когда MTA доставляет исходящее письмо, он смотрит hostname получателя, определяет IP адрес следующего почтового сервера, используя DNS, и отправляет это письмо по SMTP.

Различные параметры в конфиге Postfix настраивают различные программы (части Postfix), поэтому в начале нужно разобраться, какие программы существуют и как они работают.

Как работает Postfix

Postfix выполняет множество задач. Каждая задача выполняется отдельной программой. Когда мы запускаем Postfix, используя postfix start, запускается master демон. Он остается запущенным, пока мы не остановим Postfix командой postfix stop. Этот демон вызывает другие программы, которые выполняют свои задачи и завершают свою работу.

Каждая программа использует минимальный набор привилегий, необходимый для выполнения своих задач. Если вы хотите, чтобы Postfix был простым relay, вы можете отключить, например, программу, которая доставляет сообщения в почтовый ящик пользователя для безопасности. Таким образом, даже если злоумышленник получит доступ к одной из таких программ, он не сможет сделать больше, чем она сама.

Существует 3 основных вида программ в Postfix:

  1. Программы, которые получают письма и передают их менеджеру очередей.
  2. Менеджер очередей, который вызывает другие программы, чтобы доставить письма.
  3. Программы, которые доставляют письма различными способами.

Мы можем отправить письмо в Postfix либо локально, либо по сети.

Если мы отправляем письмо локально (напр, используя sendmail), в начале, команда postdrop оставит его в очереди maildrop. Это работает, даже когда Postfix не запущен. Все очереди Postfix, обычно, находятся в директории /var/spool/postfix, поэтому мы можем увидеть очередь maildrop в этой директории. Давайте посмотрим, как это работает.

ls /var/spool/postfix/maildrop/
sendmail root@localhost
# Subject: Тест
# Тестовое сообщение
ls /var/spool/postfix/maildrop/
# 0C2594C048B

Затем pickup демон забирает это письмо, проверяет его и передает cleanup демону.

cleanup демон вместе с trivial-rewrite демоном вставляет в письмо пропущенные заголовки, преобразует адреса в нужный формат, и изменяет их в соответствии с различными lookup таблицами (canonical, и др). Подробнее тут. Наконец, cleanup демон оставляет подготовленное письмо в incoming очереди и оповещает об этом менеджер очередей qmgr.

qmgr использует trivial-rewrite, чтобы определить способ доставки, хост для доставки, и адрес получателя. Если есть свободные ресурсы, qmgr перемещает письмо из очереди incoming в очередь active и вызывает подходящий агент доставки (smtp, lmtp, local, virtual, pipe), чтобы отправить письмо конечному получателю или перенаправить его в следующее место назначения.

Если мы отправляем письмо по сети, используя протокол SMTP, smtpd демон принимает его, проверяет, и передает cleanup демону. Остальной процесс такой же.

Если агент доставки временно не может получить письмо (возвращает 4xx, или существует временная проблема с DNS), то qmgr оставляет письмо в очереди deferred и помечает его временной меткой, когда должна произойти следующая попытка доставки. Периодически (каждые 300 секунд по умолчанию), менеджер очередей сканирует очередь deferred и проверяет эту временную метку. Если это время наступило, qmgr перемещает письмо из очереди deferred в очередь active, чтобы попытаться доставить его еще раз. После установленного временного периода (5 дней по умолчанию), Postfix перестает пытаться доставить письмо и возвращает (bounces) его назад пользователю.

Если агент доставки возвращает 5xx (постоянная проблема), bounce демон создает новое письмо с ошибкой и передает его cleanup демону, который отправляет его в очередь incoming для доставки.

Менеджер очередей также работает с defer и bounce демонами, чтобы сохранить причину, почему письмо было отложено (deferred) или должно быть возвращено (bounced). Эта информация хранится в директориях /var/spool/postfix/defer и /var/spool/postfix/bounce соответственно. Демоны defer и bounce используют информацию из этих директорий при генерации писем с ошибками.

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

Вы можете почитать подробнее об архитектуре Postfix в официальной документации.

Классы адресов в Postfix

Используя различные классы адресов, Postfix определяет, какое письмо принять, и как доставить его. В зависимости от класса адресов, менеджер очередей вызывает подходящий агент доставки, чтобы обработать данное письмо.

Каждый класс адресов состоит из 3 частей:

  1. Список доменов (будут приняты только письма, отправленные на эти домены).
  2. Список почтовых адресов получателей (будут приняты только письма, отправленные на эти адреса). Если этот список не указан, Postfix принимает любые адреса.
  3. Способ доставки (transport).

Есть 4 основных класса адресов: local, virtual alias, virtual mailbox и relay.

Класс адресов local

Когда используется класс адресов local, Postfix оставляет письма в локальных почтовых ящиках для пользователей, которые имеют системный UNIX аккаунт. Письма для различных доменов, но одинаковых пользователей, попадают в один и тот же почтовый ящик. По умолчанию, доставкой занимается агент local.

/etc/postfix/main.cf:

mydestination = $myhostname, $mydomain, /etc/postfix/mydestinations
local_recipient_maps = lmdb:/etc/postfix/local_recipients
local_transport = local

/etc/postfix/mydestinations:

domain1.com
domain2.com

/etc/postfix/local_recipients:

kate -
john -
postmap /etc/postfix/local_recipients

Класс адресов virtual alias

Когда используется класс адресов virtual alias, Postfix перенаправляет письма на другие почтовые адреса, находящиеся в других классах адресов.

/etc/postfix/main.cf:

virtual_alias_domains = /etc/postfix/virtual_alias_domains
virtual_alias_maps = lmdb:/etc/postfix/virtual_aliases

canonical_maps = lmdb:/etc/postfix/canonical

/etc/postfix/virtual_alias_domains:

domain1.com
domain2.com

/etc/postfix/virtual_aliases:

kate@domain1.com kate.brown
kate@domain2.com kate.smith
john@domain2.com john

/etc/posfix/canonical:

kate.brown kate@domain1.com
kate.smith kate@domain2.com
john john@domain2.com
postmap /etc/postfix/virtual_aliases
postmap /etc/postfix/canonical

Класс адресов virtual mailbox

Когда используется класс адресов virtual mailbox, Postfix отправляет письма в почтовые ящики, указанные в конфиге virtual_mailbox_maps. Пользователям не нужно иметь системный UNIX аккаунт. По умолчанию, доставкой занимается агент virtual.

/etc/postfix/main.cf:

virtual_mailbox_domains = /etc/postfix/virtual_mailbox_domains
virtual_mailbox_maps = lmdb:/etc/postfix/virtual_mailboxes
virtual_transport = virtual

virtual_mailbox_base = /usr/local/vmail
virtual_uid_maps = static:1000
virtual_gid_maps = static:1000

/etc/postfix/virtual_mailbox_domains:

domain1.com
domain2.com

/etc/postfix/virtual_mailboxes:

kate@domain1.com domain1.com/kate.brown/
kate@domain2.com domain2.com/kate.smith/
john@domain2.com domain2.com/john/

Ключом является почтовый адрес, значением – относительный путь до почтового ящика. Слеш в конце пути означает, что будет использоваться maildir формат для хранения писем. Удалите слеш в конце, если хотите использовать формат mbox (не рекомендуется).

postmap /etc/postfix/virtual_mailboxes

Класс адресов relay

Когда используется класс адресов relay, Postfix перенаправляет письма в другое место. Это используется, когда почтовые ящики пользователей находятся в другой системе. По умолчанию, доставкой занимается агент relay (клон агента smtp).

Примеры:

  1. MDA управляет почтовыми ящиками, не Postfix, даже если он находятся на том же сервере. Это лучше, чем если Postfix будет сохранять письма самостоятельно, потому что MDA, обычно, поддерживает quota rules, sieve filters и др. прямо из коробки. Также, возможно вы захотите использовать другой формат хранения писем, который поддерживается только MDA, напр, mdbox.
  2. Резервный MX-сервер. Если главный почтовый сервер не доступен, резервный сервер будет получать почту и оставлять ее в очереди до тех пор, пока главный почтовый сервер не будет готов принять ее. Реализацию можно найти тут.
  3. Существует несколько отделов. Каждый отдел имеет свой Postfix, размещенный на их сервере. Они не должны быть доступны из вне, но они управляют почтовыми ящиками пользователей (напр, они могут использовать класс адресов virtual mailbox). В этом случае, главный Postfix должен быть настроен как relay и распределять почту по отделам.

/etc/postfix/main.cf:

relay_domains = /etc/postfix/relay_domains
relay_recipient_maps = lmdb:/etc/postfix/relay_recipients
relay_transport = relay

transport_maps = lmdb:/etc/postfix/transport

/etc/postfix/relay_domains:

domain1.com
domain2.com

/etc/postfix/relay_recipients:

kate@domain1.com -
kate@domain2.com -
john@domain2.com -

/etc/postfix/transport:

domain1.com lmtp:[127.0.0.1]
domain2.com relay:[mail2.server.com]
postmap /etc/postfix/relay_recipients
postmap /etc/postfix/transport

Класс адресов default

Если домен не указан ни в одном из классов адресов, то будет использоваться класс адресов default для отправки в следующее место назначения (Postfix определяет куда отправить письмо, используя DNS lookups). По умолчанию, доставкой занимается агент smtp.

Чтобы Postfix не был открытым relay, убедитесь, что в smtpd_recipient_restrictions есть правило reject_unauth_destination.

/etc/postfix/main.cf:

default_transport = smtp

smtpd_recipient_restrictions = reject_unauth_destination

Пользовательский класс адресов

Существуют другие агенты доставки, которые вы можете использовать (должны быть настроены в master.cf файле). Напр, используя демон pipe, Postfix может отправлять письма вашему скрипту.

Давайте представим, что у нас есть почтовый адрес support@domain.com, куда наши клиенты отправляют письма. У нас также есть почтовый адрес для каждого сотрудника, который отвечает на эти письма: manager1@domain.com и manager2@domain.com. Мы можем создать скрипт, который отправляет все письма одному из менеджеров, используя алгоритм round-robin. Таким образом, 50% всех писем, отправленных на support@domain.com будут перенаправлены первому менеджеру, а остальные 50% – второму.

Можно одновременно использовать несколько различных классов адресов, если вы хотите, чтобы разные домены обрабатывались по-разному.

Как настроить Postfix

В директории /etc/postfix есть 2 конфигурационных файла: master.cf и main.cf. Эти файлы должны иметь права доступа 644 (кто угодно может читать, владелец может изменять) и принадлежать root. Это по умолчанию, так что не меняйте права и владельца этих файлов.

Файл master.cf содержит список демонов, запущенных master демоном. Каждая строка представляет демон и то, как он должен быть запущен. Вы можете найти, что означает каждая колонка в начале этого файла. Подробнее тут. Файл main.cf содержит настройки, используемые этими демонами по-умолчанию, но вы можете переопределить их прямо в master.cf файле, используя аргумент -o, напр, вот так -o smtpd_tls_auth_only=yes.

Файл main.cf содержит все параметры (parameter = value). Значением может быть:

  • Строка: mydestination = domain.com. Кавычки считаются частью значения, поэтому не используйте их.
  • Ссылка: mydestination = $mydomain.
  • Ссылка на файл: mydestination = /etc/postfix/mydestinations.
  • Ссылка на lookup-таблицу: mydestination = lmdb:/etc/postfix/mydestinations.
  • Список значений, даже список lookup-таблиц.

Смотрите тут какие параметры какие типы значений поддерживают.

Формат master.cf, main.cf, lookup-таблиц, alias-файлов следующий:

  • Пустые строки и строки, начинающиеся с # игнорируются.
  • Строки, которые начинаются с пробелов/табов являются продолжением предыдущей строки.

Lookup-таблицы – это индексируемые файлы, которые предоставляют быстрый доступ к хранимым значениям. После любых изменений, необходимо создать индекс, используя postmap <path>. Команда postmap -q <key> <path> позволяет выполнять запросы к lookup-таблице. Ссылка на lookup-таблицу должна иметь формат parameter = type:name, где type – это тип lookup-таблицы, а name – это ресурс, содержащий ключи и значения (для большинства типов, name – это путь до файла). Путь до файла не должен содержать расширение файла. В случае, если вам необходимо хранить только ключи в lookup-таблице, используйте любой текст в качестве значения, например, комментарий. Lookup-таблица должна использоваться, когда вы хотите хранить тысячи элементов, иначе используйте простой текстовый файл.

Пример lookup-таблицы.

/etc/postfix/canonical:

name@domain.com fullname@domain.com

/etc/postfix/main.cf:

canonical_maps = lmdb:/etc/postfix/canonical

Alias-файлы используют Sendmail-совместимый формат. Чтобы создать базу данных aliases из текстового файла, используйте postalias <path>. newaliases пересоздаст alias-файлы, указанные в параметре alias_database.

Пример alias-файла.

/etc/postfix/aliases:

# Почтовый адрес (один или несколько)
alias1: manager1@domain.com, manager2@domain.com

# Путь до файла, в который нужно добавить новые письма
alias2: /usr/local/mail/alias2_mailbox

# Команда
alias3: "|/usr/local/bin/autoreply"

# Список
alias4: :include:/usr/local/mail/alias4_list

/etc/postfix/main.cf:

# Ссылка на файл (один или несколько)
alias_maps = lmdb:/etc/postfix/aliases

# Должен быть также установлен, т.к. используется `newaliases`
alias_database = lmdb:/etc/postfix/aliases

Чтобы ограничить доставку писем на внешние команды и файлы, используйте allow_mail_to_commands и allow_mail_to_files.

Вы можете управлять файлом main.cf, используя команду postconf.

postconf myhostname # Получить
postconf myhostname=mail.domain.com # Установить
postconf -m # Список названий всех поддерживаемых lookup-таблиц

Postfix, по-умолчанию, передает логи в syslogd. Вы можете указать файл, где должны сохраняться все логи.

maillog_file = /var/log/postfix.log

# Выбрать логирование в stdout. Postfix должен быть запущен вот так `postfix start-fg`.
# maillog_file = /dev/stdout

Чтобы применить новые изменения, нужно перезапустить Postfix. Postfix завершит запущенные процессы после завершения всех своих задач, над которыми они работают, перечитает конфигурационные файлы, и продолжит получать почту без прерывания работы.

postfix reload

Чтобы проверить конфиги, запустите следующую команду. Она проверяет, нет ли в конфигах каких-то проблем, проверит корректные ли используются права доступа к директориям и файлам, и создаст недостающие директории. Если все в порядке, никаких сообщений не отобразится.

postfix check

DNS

Давайте предположим, что IP адрес вашего сервера 12.34.56.78 и домен mail.server.com. Вы хотите получить письма, отправленные на домен domain.com (напр, на support@domain.com).

Чтобы отправить письмо, MTA (агент доставки smtp в Postfix) делает по-крайней мере 2 запроса к DNS:

  1. Чтобы получить hostname MTA получателя, используя MX запись.
  2. Чтобы получить IP адрес этого hostname, используя A запись.

Таким образом, домен почтового сервера должен имет по-крайней мере A запись mail.server.com. IN A 12.34.56.78. Также крайне рекомендуется установить PTR запись 78.56.34.12.in-addr.arpa. IN PTR mail.server.com., таким образом другие почтовые сервера могут проверить hostname вашего сервера до приема писем от вас, чтобы предотвратить получение спама. Иначе, ваш почтовый сервер не сможет отправлять письма на любой почтовый сервер или ваши письма будут помечены как спам. PTR запись устанавливается на стороне провайдера сервера. Например, в Hetzner, откройте ваш сервер, перейдите на вкладку Networking, и установите reverse DNS в mail.server.com.

Домен domain.com с почтовыми ящиками должен иметь хотя бы MX запись domain.com. IN MX 10 mail.server.com.. В соответствии с RFC 974, MX записью должен быть hostname, а не IP адрес. Она также не должна быть алиасом (CNAME записью), потому что это может привести к зацикливанию при доставке почты (mail loop).

Вы также должны установить SPF и/или DKIM записи, чтобы другие почтовые сервера могли принимать ваши письма. Например, gmail требует, чтобы все отправители имели либо SPF, либо DKIM (лучше оба), иначе вы не сможете отправлять письма в gmail.

SPF запись предоставляет список разрешенных IP адресов, с которых разрешено или не разрешено отправлять письма для указанного домена. Если кто-то отправляет письмо с неразрешенного IP адреса, оно будет рассматриваться как спам и может быть отклонено. Чтобы избежать изменения IP адресов для каждого домена всякий раз, когда меняется список IP адресов, в начале создайте SPF запись (TXT) v=spf1 a:mail.server.com ~all для домена _spf.server.com (используется для проверки MAIL FROM), а затем создайте SPF запись (TXT) v=spf1 redirect=_spf.server.com для домена domain.com. Если список IP адресов изменится, просто обновите SPF запись для _spf.server.com. Также установите v=spf1 a ~all для домена mail.server.com (используется для проверки HELO/EHLO). Подробнее в RFC 7208.

DKIM запись хранит публичный ключ, который используется, чтобы проверить, что письмо было отправлено с указанного домена и оно не было изменено по пути. Почтовый сервер перед тем как отправлять исходящее письмо, создает DKIM подпись, используя приватный ключ, добавляет ее в письмо, и отправляет это письмо другому почтовому серверу, который проверяет эту подписмь, используя публичный ключ, указанный в DKIM записи (TXT). Подробнее в RFC 6376. Реализацию смотрите тут.

DMARC запись определяет действия, которые необходимо предпринять, если письмо не проходит проверку подлинности, используя SPF и DKIM. DMARC запись должна быть установлена для _dmarc.domain.com как TXT запись. Примеры: v=DMARC1; p=none; fo=1; rua=mailto:dmarc-feedback@domain.com; ruf=mailto:auth-reports@domain.com (если вы хотите получать отчеты), v=DMARC1; p=none (если не хотите). Подробнее в RFC 7489.

В итоге, вам нужно установить следующие DNS записи:

mail.server.com. IN A 12.34.56.78
78.56.34.12.in-addr.arpa. IN PTR mail.server.com
_spf.server.com. IN TXT "v=spf1 a:mail.server.com ~all"
mail.server.com. IN TXT "v=spf1 a ~all"

domain.com. IN MX 10 mail.server.com.
domain.com. IN TXT "v=spf1 redirect=_spf.server.com"
mail._domainkey.domain.com. IN TXT "v=DKIM1; k=rsa; p=<key>"
_dmarc.domain.com IN TXT "v=DMARC1; p=none; fo=1; rua=mailto:dmarc-feedback@domain.com; ruf=mailto:auth-reports@domain.com"

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

Postfix получает все MX записи, сортирует их по приоритету, по возрастанию, и в начале пробует отправить исходящее письмо первому серверу. Если первый MTA не может получить это письмо, Postfix пробует отправить его следующему серверу (смотрите smtp_skip_4xx_greeting и smtp_skip_5xx_greeting, чтобы изменить это поведение). Если у домена нет ни одной MX записи, Postfix проверяет A запись и пытается доставить письмо по IP адресу.

Чтобы получать письма для домена, вам нужно установить не только MX запись, но и добавить домен в Postfix в один из классов адресов (смотрите выше). Не указывайте домен в нескольких классах адресов.

Dovecot

Если MTA (напр, Postfix) отвечает за прием и отправку писем по SMTP (иногда также за сохранение писем в почтовые ящики), MDA/MRA (напр, Dovecot) используется для сохранения писем в почтовые ящики, управления ими (папки, квоты, и др.), и получения писем из них через POP3/IMAP. Postfix может принимать письма и передавать их Dovecot через LMTP, таким образом Postfix будет простым relay.

LMTP протокол почти такой же, как и SMTP, но он предназначен только для локального использования. После команды DATA, SMTP возвращает единственное сообщение, в котором указано было ли письмо доставлено. Если письмо не удалось сохранить в одном из почтовых ящиков, это письмо будет отклонено для всех получателей. Напротив, LMTP протокол возвращает индивидуальные сообщения для каждого получателя после команды DATA. Если письмо не удалось сохранить в почтовом ящике определенного получателя, письмо будет отклонено только для этого получателя, не влияя на его доставку другим получателям.

Есть также LDA (Local Delivery Agent), но его не рекомендуется использовать, потому что:

  1. LDA получает письма через pipe, таким образом он не может возвращать ошибки назад в Postfix.
  2. LDA запускается каждый раз, как приходит письмо. Поэтому это будет работать медленнее, чем когда используется демон, напр, LMTP.
  3. Письмо с несколькими получателями будет передано в LDA несколько раз, для каждого получателя отдельно.
  4. LDA не поддерживает dynamic recipient validation (напр, если вы храните пользователей в /etc/dovecot/users).
  5. Если вы создаете UID/GID для каждого пользователя, может возникнуть проблема с правами, т.к. Postfix запускает процессы с минимальным количество привилегий, а не под root.

Аутентификация

Dovecot делает запросы аутентификации, когда пользователь авторизуется, либо когда было получено новое письмо.

Когда пользователь авторизуется, Dovecot в начале делает запрос passdb, чтобы проверить его пароль и решает дать ли этому пользователю доступ. После этого, Dovecot использует userdb, чтобы определить UID/GID от имени которых будут сохранены файлы, и путь до его домашней директории, где хранятся почтовые файлы, sieve скрипты, и др.

Когда было получено письмо, Dovecot использует только запрос userdb, чтобы определить, где должно быть сохранено письмо (домашняя директория), и какие должны быть права у файлов (UID/GID).

Вы можете выполнять запросы к userdb и passdb, используя doveadm CLI tool. Это может быть полезно в процессе тестирования, особенно, если вы используете PostgreSQL/MySQL для хранения данных.

doveadm user my_user # запрос userdb
doveadm auth test my_user # запрос passdb

Существует множество способов, как вы можете хранить userdb и passdb. Наиболее популярные – SQL, LDAP, и passwd-file. SQL позволяет хранить данные в PostgreSQL, MySQL или SQLite. passwd-file позволяет хранить данные в одном текстовом файле (напр, в /etc/dovecot/passwd-file). Как сказал Peer Heinlein, однажды он использовал passwd-file даже для хранения более 100000 пользователей и процесс аутентификации занимал буквально несколько миллисекунд благодаря кешированию Dovecot.

Dovecot использует UID (User ID) и GID (Group ID) для управления правами доступа к почтовым ящикам пользователей. Обычно, лучше использовать один и тот же UID для всех пользователей, потому что:

  1. Проще писать скрипты, которые должны иметь доступ к почтовым ящикам. Напр, чтобы развернуть бекап.
  2. Проще реализовать shared folders.
  3. Вы можете иметь менее 2^16 UIDs в Linux kernel версии <=2.4, и 2^32 в версии >2.4.
  4. Различные UIDs дают лишь небольшую выгоду в безопасности, потому что Dovecot все равно имеет доступ к почтовым ящикам всех пользователей.

Существует 2 способа аутентификации: plaintext (PLAIN, LOGIN) и non-plaintext (SCRAM-SHA-256 и др.).

PLAIN и LOGIN оба передают пароль в виде открытого текста (должны быть использованы с SSL/TLS), но существует небольшая разница. PLAIN (RFC 4616) передает имя пользователя и пароль в виде одной строки, а LOGIN (Microsoft) – в виде двух base64-закодированых строк. При использовании plaintext вы можете хранить в базе данных все пароли зашифрованными (напр, используя ARGON2ID). Даже если злоумышленник получит доступ к этой базе данных, он не сможет прочитать пароли. Это действительно имеет смысл, потому что большинство пользователей везде использует один и тот же пароль и вы ничего не можете с этим поделать, таким образом будет не так сложно злоумышленнику написать скрипт, который будет пробовать те же пароли в других почтовых серверах (gmail, yandex и др.). Таким образом, лучше хранить все пароли зашифрованными в базе данных.

Non-plaintext обычно используется, когда пользователи могут авторизоваться без SSL/TLS соединения. Это работает следующим образом. Сервер генерирует уникальный ключ сессии при каждом входе. Клиент и сервер в последствии использует этот ключ, чтобы сгенерировать хеш пароля. Этот ключ действует только в рамках этой сессии. В этом случае, вы должны хранить все пароли в базе данных в открытом формате.

По умолчанию, Dovecot делает 2 запроса в процессе аутентификации пользователя: passdb и userdb. Чтобы не делать второй запрос, ответ на passdb запрос должен содержать не только user (или username, domain) и password, но и userdb_home, userdb_uid, и userdb_gid. Это называется prefetching. Запрос userdb все равно будет выполняться, когда было получено письмо или был произведен доступ к shared folder. Смотрите реализацию во второй части данной статьи.

Форматы хранения почтовых ящиков

Существует 3 формата хранения в Dovecot: mbox, Maildir и mdbox.

Формат mbox хранит все письма для одной IMAP папки в одном файле. Этот формат был создан для использования с POP3, где письма удаляются регулярно на почтовом сервере после их получения, чтобы избежать постоянного увеличения файла. Но когда используется IMAP, письма, обычно, остаются на почтовом сервере и редко удаляются. Это приводит к проблемам, например, когда вы удаляете письмо из середины файла размером в 1 ГБ, копируется весь файл. Кроме этого, только один процесс может работать с этим файлом (добавить новое письмо, удалить письмо, и т.д.). Как сказал Peer Heinlein: "В некоторых случаях Postfix не мог записать новое сообщение в файл mbox в течение 3-4 часов, т.к. файл был постоянно занят и заблокирован другими процессами.". Не используйте mbox.

Формат Maildir хранит каждое письмо в отдельном файле. IMAP папка – это директория с письмами в ней. Добавление нового письма – это просто создание нового файла, удаление – аналогично. Таким образом, различные процессы могут работать с тем же почтовым ящиком одновременно. Но огромное количество маленьких почтовых файлов на диске (сотни тысяч) могут значительно ухудшить производительность создания резервных копий.

Формат mdbox хранит несколько писем в одном файле, размером в несколько МБ (~100 писем в файле). Таким образом, создание бекапов намного быстрее, операция удаления не является проблемой, т.к. размер файла лишь несколько МБ (см. mdbox_rorate_size, рекомендуется установить 5-10 МБ). На самом деле, когда пользователь удаляет письмо, оно не удаляется из файла, а лишь помечается в индексе Dovecot как удаленное. Ваш скрипт должен запускать doveadm purge -A, например, каждые выходные по ночам, чтобы физически удалять все письма, помеченные как удаленные. Различные процессы могут также управлять разными файлами одновременно. Недостатком является то, что вы не можете восстановить/удалить письма или создать/удалить IMAP папки вручную, вы должны использовать команду doveadm для этого. Удаление одного из dovecot.index.* файлов (хранят ключевые фразы, IMAP флаги и др.) может привести к повреждению хранилища mdbox.

Peer Heinlein дал хорошую рекомендацию, какой формат хранения лучше выбрать. Используйте Maildir до тех пор, пока у вас не возникнут проблемы с производительностью (в особенности при создании резервной копии) и если размер вашего Maildir хранилища менее 3-4 ТБ. Нет особой проблемы мигрировать из Maildir в mdbox, когда придет время. Поэтому, если вы начинаете с нуля и у вас нет терабайт почтовых данных, начните с Maildir и используйте команду doveadm в ваших скриптах, чтобы не пришлось их менять. Пример скрипта для миграции в mdbox вы можете найти в его книге про Dovecot.

Рекомендуется хранить все почтовые данные для Dovecot, используя файловые системы ext4 или xfs с noatime. Так будет в несколько раз быстрее, по сравнению с другими файловыми системами.

Теперь, когда мы разобрались с основами, пришло время применить все это на практике. Во второй части данной статьи я покажу все кофигурационные файлы Postfix, Dovecot и Rspamd.

Похожие статьи

Как получить N строк для каждой группы в SQL

Давайте предположим, что вы разрабатываете главную страницу в интернет-магазине. На этой странице должны отображаться категории товаров с 10 товарами в каждой. Как сделать запрос к базе данных? Какие индексы нужно создать, чтобы ускорить выполнение...

Как получить N строк для каждой группы в SQL