Почтовый сервер Postfix для веб-сайта

Почтовый сервер Postfix для веб-сайта. Отправка писем с WordPress и форм

1.10.26

Сайту почта нужна почти всегда: формы обратной связи, регистрация, восстановление пароля, уведомления магазину. При этом «полный» почтовый сервер с ящиками сотрудников — отдельная история. Для веб-сайта чаще всего хватает надёжной исходящей отправки через Postfix. В этой статье покажу практичную схему под сайт (часто WordPress) и типичные грабли, из‑за которых письма уходят в спам или не уходят вовсе.

Если вам нужны виртуальные ящики для людей — смотрите отдельную заметку про Postfix + Dovecot. Здесь фокус именно на сайте.

Что обычно нужно сайту

  • Отправлять письма From: noreply@example.com или с адреса домена сайта.
  • Не принимать чужую почту с интернета (не стать open relay).
  • Чтобы PHP / WordPress могли отдать письмо локально (sendmail) или по SMTP на 127.0.0.1:25.
  • Чтобы принимающие сервера (Gmail, Яндекс, корпоративная почта) хоть как‑то доверяли отправителю.

Понятно, что «поставил Postfix и забыл» почти не бывает. Без PTR, SPF и нормального From письма будут тонуть. Про доставляемость связкой SPF + DKIM + DMARC я уже писал отдельно — к ней вернёмся в конце как к обязательному следующему шагу.

Итак, теории достаточно. Начнём.

Два рабочих сценария

1. Сайт шлёт сам через локальный Postfix

Сервер сайта = исходящий MTA. Postfix слушает только localhost, наружу отдаёт письма сам. Это простой и предсказуемый вариант для одного VPS с одним‑двумя сайтами.

2. Сайт отдаёт письма на внешний SMTP (relayhost)

Локальный Postfix — «тонкий клиент»: принимает от PHP и пересылает на SendGrid / Amazon SES / корпоративный SMTP / отдельный почтовый VPS. Удобно, если IP сайта «грязный» или провайдер режет 25 порт.

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

Установка Postfix (Ubuntu)

sudo apt update
sudo apt install postfix mailutils

В инсталляторе тип конфигурации удобнее выбрать Internet Site, если сервер сам будет доставлять наружу, или Satellite system, если весь исходящий поток уходит на relay. System mail name — ваш домен, например example.com.

Проверка, что сервис жив:

systemctl status postfix
postconf mail_version

Базовая конфигурация «под сайт, без открытого релэя»

Правим /etc/postfix/main.cf (значения подставьте свои). Идея простая: снаружи на 25 порт нас лучше не слушать, локально PHP должен достучаться.

# Имя хоста, с которым Postfix представляется миру
myhostname = mail.example.com

# Домен для неполных адресов
myorigin = /etc/mailname

# Что считаем «своим» для локальной доставки.
# Для чисто исходящего сайта часто достаточно localhost.
mydestination = localhost.$mydomain, localhost

# Сети, которым разрешено релэить через нас
mynetworks = 127.0.0.0/8 [::1]/128

# Не слушаем внешний мир на SMTP — только локально
inet_interfaces = loopback-only
inet_protocols = ipv4

# Баннер и формат
smtpd_banner = $myhostname ESMTP
append_dot_mydomain = no

После правок:

sudo postfix check
sudo systemctl reload postfix

Важно: если оставить inet_interfaces = all и ослабить ограничения, легко получить open relay. Для веб‑сайта loopback‑only — самый безопасный дефолт. Принимать почту на MX в этой схеме мы и не планируем.

DNS, которые должны быть до запуска «в прод»

  • A для mail.example.com → IP сервера сайта (или почтового хоста).
  • PTR (обратная зона) IP → тот же mail.example.com. Без PTR у многих провайдеров письма режутся сразу. PTR обычно заказывается у хостера по тикету.
  • SPF TXT на домене, если с этого IP реально уходит почта, например: v=spf1 ip4:YOUR_IP ~all.

MX для исходящего‑only сайта формально не обязателен. Но если на домене вообще нет MX, часть фильтров смотрит косо. Часто ставят MX на нормальный ящик (Google Workspace / Яндекс / отдельный почтовый сервер), а сайт шлёт с того же домена через SPF ip4: сервера сайта. Главное — не плодить несколько SPF‑записей.

Как WordPress и PHP отдают письма в Postfix

По умолчанию wp_mail() в WordPress идёт через PHP mail(), а та на Linux обычно зовёт sendmail‑совместимый бинарник Postfix (/usr/sbin/sendmail). Если Postfix локально работает — формы и системные письма WordPress уже могут уходить без SMTP‑плагина.

Быстрая проверка с сервера:

echo "Test body" | mail -s "Postfix test" you@example.com
# смотрим очередь и логи
mailq
sudo tail -n 50 /var/log/mail.log
# на некоторых системах:
# sudo journalctl -u postfix -n 50 --no-pager

Если хотите явно SMTP на localhost (плагины вроде WP Mail SMTP / FluentSMTP), хост 127.0.0.1, порт 25, без шифрования на loopback — нормальная схема. Не публикуйте этот порт наружу «для удобства».

Отдельный момент: From должен совпадать с доменом, который вы авторизуете в SPF/DKIM. Письма From: wordpress@localhost или с чужого gmail «через ваш IP» — классический путь в спам. В WordPress задайте нормальный From в настройках плагина SMTP или маленьким сниппетом на фильтры wp_mail_from / wp_mail_from_name.

Вариант с relayhost (если 25 порт закрыт или IP плохой)

relayhost = [smtp.provider.example]:587
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_tls_security_level = encrypt
smtp_use_tls = yes

Файл паролей:

# /etc/postfix/sasl_passwd
[smtp.provider.example]:587 username:password
sudo postmap /etc/postfix/sasl_passwd
sudo chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
sudo systemctl reload postfix

В SPF тогда должен быть механизм провайдера (include:), а не только IP сайта — иначе DKIM/SPF разъедутся с реальностью.

TLS для исходящих соединений

Даже если SMTP снаружи не слушаете, Postfix всё равно ходит на чужие MX. Имеет смысл включить клиентский TLS. Подробный разбор STARTTLS/сертификатов — в статье Postfix TLS/STARTTLS. Минимально часто ставят:

smtp_tls_security_level = may
smtp_tls_loglevel = 1

may — шифруем, если принимающая сторона умеет; не роняем доставку там, где TLS ещё кривой. Для параноидальных контуров уже смотрят encrypt и политики по доменам.

Типичные ошибки именно у сайт‑почты

  • Сайт шлёт с одного IP, а SPF описывает другой — получатель ставит fail. Смотрите реальный исходящий IP в логах и в заголовках письма.
  • Форма подставляет From = email посетителя. Так делать нельзя, это и спуфинг, и поломка SPF. From — ваш домен, а адрес пользователя — в Reply-To.
  • Очередь растёт, а в логах defer — серый список, временный reject, нет PTR, блок 25 порта. mailq и mail.log — первые друзья.
  • Open relay «на всякий случай» — через сутки станете частью чужого спама, IP улетит в чёрные списки. Не делайте так
  • Сразу жёсткий DMARC — сначала observe, потом quarantine/reject. Об этом тоже в гайде по SPF/DKIM/DMARC.

Как проверить, что всё работает

  1. Отправьте тестовое письмо на свою почту на Gmail/Яндекс с сервера и с формы сайта.
  2. Откройте «исходник письма» и проверьте Received, наличие нормального From, при наличии DKIM — заголовок подписи.
  3. Посмотрите Authentication-Results: желательно spf=pass, позже dkim=pass.
  4. Прогоните домен через MX Toolbox / mail-tester.com — не как истину в последней инстанции, а как быстрый чеклист.
  5. Убедитесь, что с внешней сети telnet YOUR_IP 25 не открывается, если выбран режим loopback‑only.

Что делать дальше

Когда базовая отправка с сайта заработала, следующим слоем я бы ставил:

Для веб‑сайта Postfix в режиме «только исходящие с localhost» — достаточный и надёжный фундамент. Главное не смешивать в одной голове «формы WordPress» и «корпоративную почту на 50 ящиков» без необходимости, это разные задачи и разный объём сопровождения.