Почта на своём домене

Почта на стороне провайдера или свой сервер

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

Почтовая служба провайдераСвой почтовый сервер
НастройкаСменить записи MX и создать ящикиУстановить, настроить и обслуживать две службы
ДоставляемостьЕю занимается провайдер с репутациейСвоя: строить с нуля, по одному IP за раз
СтоимостьЗа пользователя в месяцСервер, за который вы уже платите
КонтрольОграничен тем, что предлагает провайдерКаждая настройка, каждая строка журнала
ОбслуживаниеПровайдер обновляетВы обновляете Postfix, Dovecot и фильтры
Хорошо дляБизнеса, настоящего ящика, общей командыУчёбы, многих адресов, почтового шлюза, который вы понимаете

Небольшому сайту с одним ящиком лучше подойдёт служба провайдера или почта хостинга из урока 4. Стройте свой сервер, когда хотите понять, как работает почта, когда нужно много адресов или когда у вас уже есть сервер и вы хотите держать журналы в своих руках. Остальная часть урока делает именно это на той же машине с Ubuntu.

MX, SPF, DKIM, DMARC

Четыре записи решают, будет ли доставлена ваша почта, и каждая отвечает на свой вопрос.

Почтовый сервис сам даёт точные значения, и вы вставляете их в панель DNS. На своём сервере они выглядят так:

example.com. 3600 IN MX 10 mail.example.com. mail.example.com. 3600 IN A 203.0.113.10 example.com. 3600 IN TXT "v=spf1 mx -all" mail._domainkey.example.com. 3600 IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBg..." _dmarc.example.com. 3600 IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com"

Запись SPF означает: серверы из записей MX могут отправлять, а все остальные проверку не проходят (жёсткий отказ). Запись SPF на имя должна быть ровно одна, и она может вызвать не больше десяти запросов DNS. Значение DKIM длинное, и его копируют точно, без переносов строк. Проверка DMARC пройдена, когда пройдена проверка SPF или DKIM и домен в ней совпадает с доменом в заголовке From; не пройдена — когда ни одна из них не даёт совпадения. SPF проверяют по конвертному отправителю, которого релей или почтовая программа может переписать, поэтому успешная проверка SPF ещё не означает совпадения домена; DKIM подписывает сам домен From. DMARC начинают с p=none, что только сообщает; после месяца чистых отчётов его поднимают до quarantine, а затем до reject.

Обратный DNS

Прямой DNS превращает имя в адрес. Обратный DNS делает наоборот, и почтовые серверы его проверяют: письмо с IP-адреса, у которого нет обратного имени или оно не совпадает с именем в приветствии, считают подозрительным. Создать его сами вы не можете; его задаёт владелец адреса.

В панели провайдера VPS найдите настройку обратного DNS или PTR для вашего адреса IPv4 и задайте mail.example.com. Адресу IPv6 нужна своя запись PTR. Затем проверьте снаружи:

dig +short -x 203.0.113.10

mail.example.com.

Имя в ответе должно совпадать с именем, которое ваш почтовый сервер объявляет в приветствии, а это myhostname в Postfix. Несовпадение — самая частая причина, по которой новый почтовый сервер попадает в спам.

Порт 25 часто закрыт

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

sudo apt install netcat-openbsd

nc -vz alt1.gmail-smtp-in.l.google.com 25

Connection to alt1.gmail-smtp-in.l.google.com 25 port [tcp/smtp] succeeded!

Тайм-аут вместо успеха означает, что провайдер блокирует порт. Попросите поддержку открыть его — многие провайдеры делают это для проверенного аккаунта, — или отправляйте через релей: смарт-хост, который принимает вашу почту на порту 587 с аутентификацией и доставляет её за вас. Релей — практичное решение и тогда, когда у вашего IP плохая репутация и вы не хотите ждать неделями, пока она улучшится.

Postfix и Dovecot

Postfix передаёт почту между серверами; Dovecot позволяет почтовому клиенту читать ящик по IMAP. Файрвол из урока 8 разрешает только SSH и веб-порты, поэтому сначала откройте почтовые порты, иначе службы запустятся и останутся недоступными:

sudo ufw allow 25/tcp

sudo ufw allow 587/tcp

sudo ufw allow 993/tcp

Затем установите обе службы и ответьте Internet Site с example.com как системным именем почты, когда установщик спросит:

sudo apt install postfix dovecot-core dovecot-imapd

Основная настройка задаёт имя сервера, домены, для которых он принимает почту, и сертификат TLS. В main.cf Ubuntu уже есть большинство этих ключей, поэтому править файл руками значит находить каждую старую строку и удалять её. postconf -e заменяет значение на месте, одна настройка на команду:

sudo postconf -e 'myhostname = mail.example.com'

sudo postconf -e 'mydomain = example.com'

sudo postconf -e 'myorigin = $mydomain'

sudo postconf -e 'inet_interfaces = all'

sudo postconf -e 'inet_protocols = ipv4'

sudo postconf -e 'mydestination = $myhostname, $mydomain, localhost.$mydomain, localhost'

sudo postconf -e 'home_mailbox = Maildir/'

sudo postconf -e 'mynetworks = 127.0.0.0/8'

sudo postconf -e 'relay_domains ='

sudo postconf -e 'smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination'

sudo postconf -e 'smtpd_tls_cert_file = /etc/letsencrypt/live/example.com/fullchain.pem'

sudo postconf -e 'smtpd_tls_key_file = /etc/letsencrypt/live/example.com/privkey.pem'

sudo postconf -e 'smtpd_tls_security_level = may'

sudo postconf -e 'smtpd_sasl_type = dovecot'

sudo postconf -e 'smtpd_sasl_path = private/auth'

sudo postconf -e 'smtpd_sasl_auth_enable = yes'

sudo postconf -e 'smtpd_tls_auth_only = yes'

sudo systemctl reload postfix

mydestination перечисляет домены, которые этот сервер считает своими; relay_domains пуст, поэтому он ничего никому не пересылает. home_mailbox заставляет Postfix писать каждое письмо в папку Maildir пользователя, откуда его читает Dovecot. Ограничения релея разрешают почту с самой машины и от аутентифицированных пользователей и отказывают во всём остальном для внешних получателей. Именно эта строка делает открытый релей невозможным.

smtpd_tls_auth_only = yes — вторая половина замка: при глобально включённой аутентификации она заставляет Postfix отказать в пароле, пока не поднят TLS. Без неё порт 25 принял бы пароль открытым текстом до начала зашифрованного сеанса.

Порт отправки, 587, — там, откуда шлют почтовые клиенты. Клиент подключается открытым текстом, переключается на TLS через STARTTLS и только потом может аутентифицироваться. Порт 465 — другая схема, неявный TLS: там сеанс TLS начинается вместе с подключением, с первого байта.

sudo vi /etc/postfix/master.cf

submission inet n - y - - smtpd -o syslog_name=postfix/submission -o smtpd_tls_security_level=encrypt -o smtpd_sasl_auth_enable=yes -o smtpd_relay_restrictions=permit_sasl_authenticated,reject

Dovecot нужны место для ящика, TLS и сокет, который Postfix использует для проверки паролей. Их держат три файла:

sudo vi /etc/dovecot/conf.d/10-mail.conf

mail_location = maildir:~/Maildir

sudo vi /etc/dovecot/conf.d/10-ssl.conf

ssl = required ssl_cert = </etc/letsencrypt/live/example.com/fullchain.pem ssl_key = </etc/letsencrypt/live/example.com/privkey.pem

sudo vi /etc/dovecot/conf.d/10-master.conf

service auth { unix_listener /var/spool/postfix/private/auth { mode = 0660 user = postfix group = postfix } }

Блок вставляют внутрь существующего раздела service auth { }, где он заменяет закомментированный слушатель с тем же именем, который уже положил туда пакет.

Перезапустите обе службы и создайте первый ящик как системного пользователя — это простейшая схема для нескольких адресов:

sudo systemctl restart postfix dovecot

sudo adduser you

Аккаунт входит в IMAP как you со своим системным паролем, на порт 993 с TLS, и отправляет на порт 587 с STARTTLS. Более крупная схема хранит пользователей в базе данных, и это та же схема, только частей больше.

Подпись DKIM

DKIM подписывает каждое исходящее письмо закрытым ключом, а открытый ключ лежит в записи TXT, чтобы получатели могли проверить подпись. Сгенерируйте ключ на 2048 бит для селектора mail:

sudo apt install opendkim opendkim-tools

sudo mkdir -p /etc/dkimkeys

sudo opendkim-genkey -b 2048 -v -d example.com -s mail -D /etc/dkimkeys

opendkim-genkey: generating private key opendkim-genkey: private key written to mail.private opendkim-genkey: extracting public key opendkim-genkey: DNS TXT record written to mail.txt

opendkim-genkey молчит, если не задан -v, поэтому в команде выше он есть. Команда работает от root, поэтому закрытый ключ принадлежит root, а служба OpenDKIM, которая работает под opendkim, не может его прочитать и ничего не подписала бы. Отдайте ключ этому пользователю:

sudo chown opendkim:opendkim /etc/dkimkeys/mail.private

Файл /etc/dkimkeys/mail.txt содержит запись DNS; опубликуйте его содержимое как запись TXT на mail._domainkey.example.com. Файл разбивает длинный ключ на несколько строк в кавычках для читаемости; соедините их в одно значение, без пробелов и переносов строк.

Затем скажите OpenDKIM, какой ключ подписывает какой домен. В /etc/opendkim.conf Ubuntu уже есть активная строка Socket, local:/run/opendkim/opendkim.sock: замените эту строку на inet-сокет ниже, не добавляйте вторую:

sudo vi /etc/opendkim.conf

Domain example.com Selector mail KeyFile /etc/dkimkeys/mail.private Socket inet:12301@localhost

Подключите Postfix к милтеру, затем перезапустите обе службы:

sudo postconf -e 'milter_default_action = accept'

sudo postconf -e 'smtpd_milters = inet:localhost:12301'

sudo postconf -e 'non_smtpd_milters = inet:localhost:12301'

sudo systemctl restart opendkim postfix

dig +short TXT mail._domainkey.example.com

"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..."

Цель — подпись, которая проверяется у получателя, а не запись, которая существует. Отправьте письмо в ящик у крупного провайдера и прочитайте его заголовки, как показывает раздел о проверке.

TLS для почты, без открытого релея

Сертификат для mail.example.com получают через certbot, как любой другой. Добавьте имя в блок сервера сайта, чтобы проверка по HTTP могла до него добраться:

sudo vi /etc/nginx/sites-available/example.com

server_name example.com www.example.com mail.example.com;

sudo nginx -t

sudo systemctl reload nginx

Затем выпустите один сертификат на все три имени:

sudo certbot --nginx -d example.com -d www.example.com -d mail.example.com

Postfix и Dovecot теперь читают файлы из /etc/letsencrypt/live/example.com/: certbot называет папку по первому домену в команде, а сам сертификат покрывает все три. Плагин nginx у certbot перезагружает только nginx, поэтому Postfix и Dovecot нужен свой хук развёртывания; каждое продление его запускает:

sudo vi /etc/letsencrypt/renewal-hooks/deploy/reload-mail.sh

#!/bin/sh systemctl reload postfix dovecot

sudo chmod 755 /etc/letsencrypt/renewal-hooks/deploy/reload-mail.sh

Теперь докажите, что сервер не пересылает. С другой машины подключитесь к порту 25 и попробуйте отправить письмо на адрес, который вам не принадлежит. Сервер должен отказать с ошибкой релея:

swaks --to someone@example.net --server 203.0.113.10:25

<** 554 5.7.1 <someone@example.net>: Relay access denied

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

Отправка с сайта

Форме обратной связи лучше не использовать функцию mail() в PHP через локальную очередь: письмо, отправленное так, не имеет аутентификации, и его легко пометить как спам. Отправляйте через порт отправки с аутентификацией. msmtp — небольшой клиент SMTP, который PHP может вызывать вместо sendmail:

sudo apt install msmtp

Ставьте только msmtp, а не пакет msmtp-mta: тот заменяет Postfix как локальный агент передачи почты, а этому серверу нужен Postfix.

sudo mkdir -p /etc/msmtp

sudo vi /etc/msmtp/example.conf

defaults auth on tls on tls_trust_file /etc/ssl/certs/ca-certificates.crt account example host mail.example.com port 587 user you password a-long-random-password from you@example.com account default : example

sudo chown root:example /etc/msmtp/example.conf

sudo chmod 640 /etc/msmtp/example.conf

Логин — you, системный пользователь из шага с ящиком, а не полный адрес: Dovecot аутентифицирует системных пользователей по имени. Адрес отправителя остаётся you@example.com.

Файл принадлежит root и группе сайта, поэтому процесс PHP может прочитать пароль, а другие пользователи — нет. Затем направьте на него пул сайта. sendmail_path — системная настройка, поэтому она идёт в пул через php_admin_value:

sudo vi /etc/php/8.3/fpm/pool.d/example.com.conf

php_admin_value[sendmail_path] = /usr/bin/msmtp -t --file=/etc/msmtp/example.conf

sudo systemctl reload php8.3-fpm

Теперь форма может отправлять через ваш сервер, с TLS и настоящим адресом отправителя. Никогда не кладите пароль SMTP в веб-корень; утёкший файл .env — одна из угроз из урока 7.

Проверка через swaks и заголовки

Bash и почтового клиента недостаточно, чтобы отлаживать почту. swaks — одна команда, которая говорит на SMTP и печатает весь разговор:

sudo apt install swaks

swaks --to you@gmail.com --from you@example.com --server mail.example.com:587 --auth LOGIN --auth-user you --auth-password "your-password" --tls

<- 250 2.0.0 Ok: queued as 4Xy2Z -> QUIT <- 221 2.0.0 Bye === Connection closed with remote host.

Письмо в очереди — только половина доказательства. В ящике получателя откройте полные заголовки и найдите результаты аутентификации:

Authentication-Results: mx.google.com; spf=pass (google.com: domain of you@example.com designates 203.0.113.10 as permitted sender) smtp.mailfrom=you@example.com; dkim=pass header.i=@example.com header.s=mail header.b=AbCdEfGh; dmarc=pass (p=NONE sp=NONE) header.from=example.com

Три отметки pass означают, что записи верны. spf=fail означает, что вашу почту шлёт адрес, которого нет в записи; dkim=fail — что селектор, ключ или подпись неверны. dmarc=fail появляется, только когда ни SPF, ни DKIM не прошли с совпадением домена: обе проверки не пройдены или обе пройдены для домена, отличного от домена в заголовке From, а это и даёт релей, переписывающий конвертного отправителя. Читайте первую ошибку, а не последнюю.

Если письмо попадает в спам, хотя все три проверки пройдены, обычная причина — репутация IP. Проверьте адрес по публичным блок-листам на check.spamhaus.org и на mxtoolbox.com. Попавший в список адрес нужно очистить, а затем попросить об удалении; пока он в списке, большинство получателей откажут или отправят вашу почту в карантин.

MTA-STS и отчёты

Две необязательные записи делают почту надёжнее, и обе стоит добавить, когда основные проверки проходят.

MTA-STS публикует политику, которая говорит, что почта на ваш домен должна идти по TLS. Ей нужна запись TXT и небольшая страница по HTTPS:

_mta-sts.example.com. 3600 IN TXT "v=STSv1; id=20261106T000000"

Саму политику отдают по адресу https://mta-sts.example.com/.well-known/mta-sts.txt:

version: STSv1 mode: testing mx: mail.example.com max_age: 86400

Начните с mode: testing и читайте отчёты; переключитесь на enforce, когда каждый важный для вас отправитель всё ещё доставляет. TLS-RPT — канал отчётов о сбоях TLS:

_smtp._tls.example.com. 3600 IN TXT "v=TLSRPTv1; rua=mailto:tlsrpt@example.com"

Обе записи легко добавить и легко забыть. Запишите их вместе со значениями MX и SPF и проверяйте снова после любого изменения почтового сервера.

Тест

1 Что говорит запись MX домена?

  1. Какие серверы могут отправлять почту за домен
  2. Куда доставляется почта для домена
  3. Какой ключ подписывает исходящие письма
  4. Что делать, когда аутентификация не прошла
Ответ

b) MX называет почтовые серверы назначения, с приоритетом. SPF — список разрешённых отправителей, DKIM — подпись, DMARC — политика.

2 Ваша запись SPF — v=spf1 mx -all. Что означает -all?

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

b) Минус означает жёсткий отказ. Используйте ~all во время переезда, когда некоторые отправители ещё не в списке.

3 Зачем новому почтовому серверу совпадающая запись PTR?

  1. Получатели проверяют, что адрес принадлежит имени, которое объявляет сервер
  2. Она ускоряет IMAP
  3. Она подписывает DKIM
  4. Она шифрует порт 25
Ответ

a) Отсутствующее или несовпадающее обратное имя — сильный сигнал спама. PTR задаёт владелец адреса, то есть провайдер VPS, а не ваша панель DNS.

4 nc -vz alt1.gmail-smtp-in.l.google.com 25 выдаёт тайм-аут. Что это значит?

  1. Gmail лежит
  2. Исходящий порт 25 заблокирован провайдером или сетью
  3. Сертификат истёк
  4. Postfix не установлен
Ответ

b) Тайм-аут на исходящем 25 — классическая блокировка. Попросите провайдера открыть его или отправляйте через релей на порту 587.

5 Какая настройка Postfix не даёт серверу стать открытым релеем?

  1. mydestination со списком всех доменов
  2. smtpd_relay_restrictions, разрешающая только аутентифицированных пользователей и локальную почту
  3. Запуск Postfix на порту 25
  4. Добавление ключа DKIM
Ответ

b) Ограничения релея решают, кто может отправлять почту на внешние домены. Проверка с другой машины должна ответить Relay access denied.

6 Письмо приходит с spf=pass, dkim=fail и dmarc=fail. Куда смотреть первым?

  1. Запись SPF
  2. Селектор, ключ и запись DNS для DKIM
  3. Запись PTR
  4. Политику MTA-STS
Ответ

b) SPF прошёл, но без совпадения домена с заголовком From, поэтому проверка DMARC всё равно не пройдена: конвертный отправитель принадлежит другому домену, например релею или почтовой программе, а заголовок From говорит ваш домен. DKIM подписывает сам домен From, поэтому исправлять надо его: сравните селектор в подписи с записью TXT и ключом на диске.

7 Зачем отправлять почту сайта через аутентифицированный SMTP, а не через локальную очередь mail()?

  1. Так быстрее
  2. Письмо несёт аутентификацию и настоящего отправителя, поэтому получатели доверяют ему больше
  3. Так не нужны записи DNS
  4. Так шифруется сайт
Ответ

b) Аутентифицированная отправка на порт 587 с TLS — то, что получающая сторона ждёт от настоящего почтового домена. Она ещё и держит пароль SMTP вне кода веб-приложения.

Автор статьи: Arthur Isaev

Изображение баннера