Зачем понимать SMTP
Простой текстовый протокол, но вокруг, лес: куча версий, расширений, 3 порта, anti-spam-стандарты (SPF/DKIM/DMARC), трёхслойная иерархия (MUA → MSA → MTA → MTA → MDA → MUA). Когда надо:
- Поднять corp-mail-сервер (Postfix/Exim для outbound; Dovecot для IMAP)
- Настроить relay-host для приложений ("отправляй уведомления через X")
- Дебажить почему "письма не доходят" (это всегда DNS + SPF + DMARC)
- Понять что показывает
journalctl -u postfixпри ошибке
Современные тренды: внутренние почтовики уходят в SaaS (Google Workspace, Microsoft 365). Self-hosted SMTP остаётся для outbound (заявки, нотификации) и в нишах где нельзя cloud (compliance, gov).
Три порта
| Порт | Что | Шифрование |
|---|---|---|
| 25 (smtp) | server-to-server, MTA-MTA | opportunistic STARTTLS |
| 587 (submission) | клиент → его MTA, с аутентификацией | STARTTLS обязательный |
| 465 (smtps) | то же что 587 но implicit TLS | TLS с handshake (legacy, RFC 8314 reissued его) |
| 2525 | non-standard, иногда у hosted-relay (SendGrid и др) | STARTTLS |
- 25 на исходящий из домашних/ISP-сетей часто заблокирован оператором (anti-spam). Оттуда шлём через 587 на свой MTA.
- 587, современный для клиентов. Auth обязателен.
- 465 был deprecated в 1998, возрождён в 2018 (RFC 8314) для клиентов, которым STARTTLS-handshake стартует в plaintext (можно downgrade-attack'ом убрать STARTTLS-extension).
SMTP-сессия (вживую)
$ telnet smtp.example.com 25
Trying 198.51.100.10...
Connected.
220 mail.example.com ESMTP Postfix
> EHLO client.example.org
250-mail.example.com Hello client
250-PIPELINING
250-SIZE 52428800
250-STARTTLS
250-AUTH PLAIN LOGIN
250 ENHANCEDSTATUSCODES
> MAIL FROM:<sender@example.org>
250 2.1.0 Ok
> RCPT TO:<rcpt@example.com>
250 2.1.5 Ok
> DATA
354 End data with <CR><LF>.<CR><LF>
> Subject: hello
>
> body
> .
250 2.0.0 Ok: queued as ABC123
> QUIT
221 2.0.0 Bye
Текстовый, можно дебажить пальцами. EHLO (вместо HELO) запрашивает расширения (ESMTP). STARTTLS, AUTH, SIZE, extensions.
DNS: MX-запись
Чтобы кто-то знал, на какой сервер слать почту для example.com:
example.com. IN MX 10 mail.example.com.
example.com. IN MX 20 backup-mail.example.com.
- 10, 20, priority. Меньше = выше приоритет. MTA пробует в порядке возрастания priority.
- Несколько MX той же priority = round-robin.
Проверка через cmd-dig:
dig example.com MX +short
Если нет MX-записи, почта идёт на A/AAAA домена (RFC 5321 §5.1).
SPF, кто может слать от моего домена
TXT-запись в DNS:
example.com. IN TXT "v=spf1 ip4:198.51.100.10 include:_spf.google.com -all"
Получающий MTA смотрит SPF-запись src-домена и проверяет: подключающийся
IP, в разрешённом списке? Если нет, -all (hard fail) → отклонить.
Механизмы:
ip4:/ip6:, конкретные IP/подсетиa, любой A-record доменаmx, любой MX-targetinclude:other.com, наследовать SPF другого домена~all(soft fail), пометить как подозрительное-all(hard fail), отклонить
SPF ломается на forwarding (forwarder ставит свой src, не оригинальный). Решение, DKIM.
DKIM, подпись писем
MTA подписывает выходящие письма приватным ключом, публичный лежит в DNS:
default._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIGfMA0..."
Получатель смотрит DKIM-Signature хедер, достаёт публичный ключ
через DNS, проверяет подпись от headers + body. Если совпало
письмо точно от этого домена и не модифицировано.
В отличие от SPF, DKIM-подпись переживает forwarding (если forwarder не правит body).
DMARC, политика для receiver'а
Оркестрирует SPF + DKIM:
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com; pct=100"
p=none, только репорты, не действоватьp=quarantine, в спамp=reject, отброситьrua=, куда слать aggregate-репортыpct=, на какой % писем применять политику (для постепенного rollout'а)
Минимальный требуемый сетап для outbound: SPF + DKIM + DMARC. Без них Gmail/Outlook/etc. с большой вероятностью бросят в спам.
Postfix vs Exim
| Признак | Postfix | Exim |
|---|---|---|
| Default где | Ubuntu, RHEL | Debian (исторически) |
| Конфиг | main.cf + master.cf, Си-стиль | exim.conf, мощнее DSL |
| Архитектура | модульная, много мелких процессов | один большой бинарь |
| Сложность learning curve | средняя | высокая |
| Production кто использует | большинство | Cambridge, kafka-mailing |
Для нового сетапа, Postfix. Exim, если уже унаследовал.
Минимальный outbound через Postfix
/etc/postfix/main.cf:
myhostname = mail.example.com
mydomain = example.com
myorigin = $mydomain
inet_interfaces = all
inet_protocols = ipv4
mydestination = $myhostname, localhost.$mydomain, localhost
# Relay - только из локальной сети (чтобы не быть open relay)
mynetworks = 127.0.0.0/8, 10.0.0.0/24
# TLS server
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem
smtpd_tls_security_level = may # opportunistic
smtpd_tls_loglevel = 1
# TLS client (для outbound)
smtp_tls_security_level = may
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
postfix check # синтаксис
systemctl reload postfix
postqueue -p # очередь
postsuper -d ALL deferred # очистить deferred (осторожно!)
Когда что-то пошло не так
relay access denied, отправляешь не из mynetworks без auth. Либо добавь IP в mynetworks, либо требуй SMTP AUTH через 587.- Письма уходят, но в спам, нет/неправильный SPF/DKIM/DMARC. Проверка через https://mail-tester.com или Gmail "show original".
Connection timed outна 25, оператор блокирует исходящий 25. Используй 587 на relayhost.- Очередь deferred растёт, receiver greylisting (вернёт 451
на первую попытку, ждёт повтор). Норма для Gmail.
mailq, посмотреть что застряло. Helo command rejected: need fully-qualified hostnamemyhostnameне FQDN или PTR-запись на IP не совпадает с EHLO.SSL_connect:errorна STARTTLS, устаревший cipher на одной стороне;smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1.- Письма back-to-self не доходят,
mydestinationне содержит локальный домен, MTA пытается забэкапить через DNS, MX резолвит в себя, петля.