# SMTP и MTA - доставка email _Протоколы · LinuxLab Knowledge Base_ **TL;DR:** SMTP - текстовый протокол доставки почты. 25/tcp - server-to-server, 587 - submission (клиент с auth), 465 - implicit-TLS legacy. MX-запись в DNS, STARTTLS+SPF+DKIM+DMARC - стандартный набор. ## Зачем понимать 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: 250 2.1.0 Ok > RCPT TO: 250 2.1.5 Ok > DATA 354 End data with . > 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](/kb/cmd-dig.md): ```bash 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-target - `include: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`: ```ini 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 ``` ```bash 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 hostname`** `myhostname` не FQDN или PTR-запись на IP не совпадает с EHLO. - **`SSL_connect:error` на STARTTLS**, устаревший cipher на одной стороне; `smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1`. - **Письма back-to-self не доходят**, `mydestination` не содержит локальный домен, MTA пытается забэкапить через DNS, MX резолвит в себя, петля. ## Команды ```bash dig example.com MX +short ``` MX-записи домена - первое что смотреть в email-routing ```bash dig example.com TXT +short | grep spf ``` SPF-запись - кому разрешено слать от этого домена ```bash dig default._domainkey.example.com TXT +short ``` DKIM публичный ключ для selector 'default' - проверка существования ```bash dig _dmarc.example.com TXT +short ``` DMARC-политика домена - reject/quarantine/none ```bash openssl s_client -starttls smtp -connect mail.example.com:25 -crlf ``` Подключиться с STARTTLS - проверить TLS-сертификат и доступность ```bash postqueue -p ``` Очередь Postfix - что застряло, почему (deferred reason) ```bash journalctl -u postfix -f --since '5 min ago' ``` Логи Postfix в реальном времени - первое место смотреть ## См. также - [DNS resolution](/kb/dns-resolution.md) - [TLS handshake](/kb/tls-handshake.md) - [dig - DNS-разведка с подробностями](/kb/cmd-dig.md) - [SSH - secure shell](/kb/ssh.md) - [LDAP - directory services основы](/kb/ldap-basics.md) - [TLS-сертификаты - X.509, цепочка доверия, Let's Encrypt](/kb/tls-certificates.md) - [GPG/PGP - подпись, шифрование, web of trust](/kb/gpg-pgp.md)