"Быстрый
<br />
Письма не уходят с Linux-сервера в 80% случаев по одной из трёх причин: провайдер заблокировал порт 25, IP не в SPF-записи, или MTA вообще не запущен. Проверяй в таком порядке: <strong>systemctl status postfix</strong> → <strong>telnet aspmx.l.google.com 25</strong> → <strong>dig TXT домен +short | grep spf</strong>. Если всё три ок — читай дальше, там глубже.<br />
<h2>Диагноз: сервер молчит, письма не уходят, клиент уже пишет</h2>
<p>Настроил рассылку. Или форму обратной связи. Или переехал на новый VPS. И тишина. В логах — «deferred», «relay access denied», «connection refused». Клиент пишет что не получил письмо. Дедлайн через час.</p>
<p>Знакомо. Видел это раз триста. И каждый раз причина одна из пяти — просто не всегда очевидно, которая именно.</p>
<p>Вот что получишь после прочтения: понимание почему вообще это ломается, пошаговую <a title="Troubleshooting сетевых проблем: 15 команд для диагностики в Windows и Linux" href="https://it-apteka.com/troubleshooting-setevyh-problem-15-komand-dlja-diagnostiki-v-windows-i-linux/" target="_blank" rel="noopener" data-wpil-monitor-id="1489">диагностику с командами</a> copy-paste, отдельные разделы для Postfix и Exim, разбор SMTP-кодов ошибок, диагностику TLS/STARTTLS, настройку relay через внешние сервисы и скрипт автодиагностики. Времени: 15 минут если проблема типовая, 40 — если всё плохо.</p>
<p>Что нужно: root или sudo на сервере, пара утилит и нежелание гуглить каждую ошибку отдельно.</p>
<pre><code class="language-bash">
# Установить всё нужное сразу:
# Debian/Ubuntu:
apt-get install -y telnet openssl mailutils dnsutils curl swaks
# CentOS/RHEL/Rocky:
yum install -y telnet openssl mailx bind-utils curl
# swaks отдельно (нет в базовых репах):
curl -L https://jetmore.org/john/code/swaks/files/swaks -o /usr/local/bin/swaks
chmod +x /usr/local/bin/swaks
</code></pre>
<hr />
<h2>Пять причин — и одна из них твоя</h2>
<p>Перед тем как лезть в конфиги — обозначим врага. Проблемы с отправкой почты с Linux-сервера делятся ровно на пять групп. Почти всегда это одна из них.</p>
<p><strong>1. Заблокирован порт 25 провайдером.</strong> Самая частая причина на новых VPS. AWS, Hetzner, DigitalOcean, Selectel — все по умолчанию режут исходящий порт 25 против спама. Твой Postfix исправно пытается отправить, а на уровне <a class="wpil_keyword_link" title="Сети" href="https://it-apteka.com/category/networks/" target="_blank" rel="noopener" data-wpil-keyword-link="linked" data-wpil-monitor-id="1480">сети</a> его уже нет. Решение: либо тикет провайдеру, либо SMTP relay через порт 587.</p>
<p><strong>2. MTA не запущен или сломан конфиг.</strong> Postfix упал тихо ночью. Exim не слушает нужный интерфейс. Конфиг сломался после apt upgrade. Очередь переполнена и заморожена. Смешно, но 20% случаев — именно это.</p>
<p><strong>3. DNS: SPF, DKIM, DMARC, PTR.</strong> Письмо уходит с сервера, но Gmail его отбивает или кидает в спам. IP не включён в SPF. DKIM-подписи нет. PTR-записи нет — сервер «анонимный», и это красный флаг для всех серьёзных почтовых систем.</p>
<p><strong>4. IP в чёрном списке.</strong> Предыдущий арендатор VPS с этого IP рассылал спам. Или ты сам случайно отправил тысячу писем в цикле. Теперь IP в DNSBL — письма молча отбиваются без объяснений.</p>
<p><strong>5. Проблема аутентификации SMTP.</strong> SASL auth не настроен. TLS не работает. Приложение пытается подключиться без авторизации, а relay запрещён. Итог: «relay access denied» или «authentication required».</p>
"Правило
<br />
В 80% случаев виноваты пункты 1 и 3. Начни с них — сэкономишь час жизни.<br />
<hr />
<h2>Как работает путь письма: схема</h2>
<p>Прежде чем диагностировать — пойми где именно рвётся цепочка. Каждый узел может быть точкой отказа.</p>
<pre class="mermaid">%%{init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#ffffff',
'primaryTextColor': '#1e293b',
'primaryBorderColor': '#94a3b8',
'lineColor': '#64748b',
'fontSize': '15px',
'fontFamily': 'ui-sans-serif, system-ui, sans-serif'
},
'flowchart': {'curve': 'linear', 'nodeSpacing': 45, 'rankSpacing': 50}
}}%%
flowchart TD
APP["Приложение / PHP mail()\nSendmail / CLI"]
MTA["MTA (Postfix / Exim)\nОчередь отправки"]
PORT["Порт 25 / 587\nФайрвол / Провайдер"]
DNS_LOOKUP["DNS lookup\nMX-запись получателя"]
REMOTE["Принимающий SMTP\nGmail / Outlook / etc"]
SPAM_CHK["Проверки на приёмной стороне\nSPF / DKIM / DMARC / Blacklist"]
INBOX["Входящие получателя"]
SPAM["Спам / Отказ\n550 / 421 / deferred"]
APP -->|"sendmail() / SMTP"| MTA
MTA -->|"Очередь → отправка"| PORT
PORT -->|"TCP соединение"| DNS_LOOKUP
DNS_LOOKUP -->|"Резолв MX"| REMOTE
REMOTE -->|"Проверка отправителя"| SPAM_CHK
SPAM_CHK -->|"Прошёл"| INBOX
SPAM_CHK -->|"Не прошёл"| SPAM
style APP fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#1e40af
style MTA fill:#f8fafc,stroke:#f97316,stroke-width:2px,color:#c2410c
style PORT fill:#f8fafc,stroke:#ef4444,stroke-width:2px,color:#b91c1c
style DNS_LOOKUP fill:#f8fafc,stroke:#94a3b8,stroke-width:2px,color:#1e293b
style REMOTE fill:#f8fafc,stroke:#94a3b8,stroke-width:2px,color:#1e293b
style SPAM_CHK fill:#f8fafc,stroke:#f97316,stroke-width:2px,color:#c2410c
style INBOX fill:#f8fafc,stroke:#22c55e,stroke-width:2px,color:#15803d
style SPAM fill:#f8fafc,stroke:#ef4444,stroke-width:2px,color:#b91c1c
</pre>
<p><em>Схема 1: Путь письма от приложения до входящих. Каждый узел — потенциальная точка отказа. <a title="nslookup и dig — диагностика DNS для системного администратора" href="https://it-apteka.com/nslookup-i-dig-diagnostika-dns-dlja-sistemnogo-administratora/" target="_blank" rel="noopener" data-wpil-monitor-id="1483">Диагностику начинай с MTA и PORT —</a> там рвётся чаще всего.</em></p>
<hr />
<h2>Шаг 1 — Проверить запущен ли MTA</h2>
<p>Смешно, но с этого надо начинать. Postfix падает тихо. После apt upgrade конфиг может не загрузиться. После перезагрузки сервера — не запуститься автоматически, если кто-то забыл enable.</p>
<h3>Postfix</h3>
<pre><code class="language-bash">
# Статус:
systemctl status postfix
# Ищи: Active: active (running)
# Если нет:
systemctl start postfix
systemctl enable postfix
# Проверить конфиг перед запуском:
postfix check
# Тихо = конфиг ок. Ошибки — будут выведены.
# Посмотреть на каком порту и интерфейсе слушает:
ss -tlnp | grep -E ':(25|587|465)'
# Должно быть: LISTEN 0 100 0.0.0.0:25 ...
</code></pre>
<h3>Exim</h3>
<pre><code class="language-bash">
# Статус (Debian/Ubuntu — exim4, CentOS — exim):
systemctl status exim4
systemctl status exim
# Запустить если не работает:
systemctl start exim4
systemctl enable exim4
# Проверить конфиг Exim:
exim -bV
# Покажет версию и список встроенных модулей
# Синтаксис конфига:
exim -C /etc/exim4/exim4.conf.template -bV 2>&1 | grep -i error
</code></pre>
<p>Если <code>ss -tlnp | grep ':25'</code> возвращает пустоту — MTA не слушает порт. Либо не запущен, либо в конфиге <code>inet_interfaces</code> настроен не так.</p>
<hr />
<h2>Шаг 2 — Проверить порты</h2>
<p>Порт 25 — классика, которую режут все подряд. AWS, Hetzner, DigitalOcean блокируют исходящий 25 по умолчанию. Узнать это можно только попробовав.</p>
<pre><code class="language-bash">
# Проверить исходящий порт 25 с сервера (к MX Google):
telnet aspmx.l.google.com 25
# "Connected to aspmx.l.google.com" + баннер "220" = порт открыт
# Timeout или "Connection refused" = провайдер режет
# Без интерактива:
timeout 10 bash -c 'echo QUIT | telnet aspmx.l.google.com 25 2>&1' | grep -E "220|refused|timeout"
# Альтернатива через curl:
curl -v telnet://aspmx.l.google.com:25 2>&1 | head -15
</code></pre>
<pre><code class="language-bash">
# Проверить порт 587 (submission):
telnet localhost 587
telnet smtp.gmail.com 587
# Проверить порт 465 (SMTPS):
openssl s_client -connect localhost:465
# Посмотреть файрвол на сервере:
# UFW:
ufw status verbose
# iptables:
iptables -L -n | grep -E "smtp|25|587|465"
# firewalld:
firewall-cmd --list-all
</code></pre>
"Порт
<br />
Открой тикет провайдеру — объясни что ты легальный отправитель. Или сразу переходи на SMTP relay через порт 587. Для большинства задач это правильнее: не надо следить за репутацией IP, не надо бороться с blacklist-ами.<br />
<hr />
<h2>Шаг 3 — Диагностика Postfix: очередь и логи</h2>
<h3>Просмотр очереди</h3>
<pre><code class="language-bash">
# Вся очередь:
mailq
# или:
postqueue -p
# Сколько писем застряло:
postqueue -p | tail -1
# Детали конкретного письма по ID из mailq:
postcat -q ABCDEF1234
# Принудительно отправить всё из очереди:
postqueue -f
# Удалить все письма (осторожно — необратимо):
postsuper -d ALL
# Удалить только deferred:
postsuper -d ALL deferred
# Удалить письма конкретного отправителя:
mailq | grep "^[A-F0-9]" | awk '{print $1}' | \
xargs -I{} postcat -q {} | grep -l "sender@example.com" | \
xargs postsuper -d
</code></pre>
<h3>Логи Postfix</h3>
<pre><code class="language-bash">
# Последние 100 строк:
tail -100 /var/log/mail.log
# На CentOS/Rocky:
tail -100 /var/log/maillog
# Только ошибки:
grep -iE "error|reject|deferred|bounced|failed|refused" /var/log/mail.log | tail -50
# Следить в реальном времени (пока тестируешь):
tail -f /var/log/mail.log
# Что происходило с конкретным письмом (по адресу получателя):
grep "recipient@gmail.com" /var/log/mail.log | tail -20
# Все попытки отправки за последний час:
grep "$(date '+%b %e %H')" /var/log/mail.log | grep "status="
</code></pre>
<h3>Минимальный рабочий конфиг Postfix</h3>
<p>Если хочешь начать с чистого листа — вот конфиг, который работает на большинстве серверов без сюрпризов:</p>
<pre><code class="language-text">
# /etc/postfix/main.cf
myhostname = mail.yourdomain.com
mydomain = yourdomain.com
myorigin = $mydomain
inet_interfaces = all
inet_protocols = ipv4
# Локальная доставка — убери домен если не принимаешь почту на этот сервер:
mydestination = $myhostname, localhost.$mydomain, localhost
# Только локальные клиенты без авторизации:
mynetworks = 127.0.0.0/8
# Размер письма 50MB:
message_size_limit = 52428800
# TLS:
smtpd_tls_cert_file = /etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file = /etc/ssl/private/ssl-cert-snakeoil.key
smtpd_tls_security_level = may
smtp_tls_security_level = may
# SASL auth:
smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_security_options = noanonymous
# Ограничения:
smtpd_recipient_restrictions =
permit_sasl_authenticated,
permit_mynetworks,
reject_unauth_destination
</code></pre>
<pre><code class="language-bash">
# Применить конфиг:
postfix check && systemctl reload postfix
</code></pre>
<hr />
<h2>Шаг 4 — Диагностика Exim: очередь, логи, конфиг</h2>
<p>Exim стоит по умолчанию на <a class="wpil_keyword_link" title="Debian" href="https://it-apteka.com/tag/debian/" target="_blank" rel="noopener" data-wpil-keyword-link="linked" data-wpil-monitor-id="1479">Debian</a> и многих хостингах. Логика та же — очередь, логи, конфиг <a title="Docker Compose — установка, команды и настройка контейнеров" href="https://it-apteka.com/docker-compose-ustanovka-komandy-i-nastrojka-kontejnerov/" target="_blank" rel="noopener" data-wpil-monitor-id="1486">— но команды</a> другие. Смешивать с Postfix не надо: либо одно, либо другое.</p>
<h3>Очередь Exim</h3>
<pre><code class="language-bash">
# Список писем в очереди:
exim -bp
# Количество писем:
exim -bpc
# Принудительно отправить все (включая frozen):
exim -qff
# Детали конкретного письма по ID:
exim -Mvl ИДЕНТИФИКАТОР
# Заголовки:
exim -Mvh ИДЕНТИФИКАТОР
# Тело:
exim -Mvb ИДЕНТИФИКАТОР
# Удалить конкретное письмо:
exim -Mrm ИДЕНТИФИКАТОР
# Удалить все замороженные (frozen):
exiqgrep -iz | xargs exim -Mrm
# Удалить всё из очереди:
exiqgrep -i | xargs exim -Mrm
</code></pre>
<h3>Логи Exim</h3>
<pre><code class="language-bash">
# Основной лог:
tail -100 /var/log/exim4/mainlog
# Только ошибки:
grep -iE "fail|reject|error|frozen|bounce" /var/log/exim4/mainlog | tail -50
# Следить в реальном времени:
tail -f /var/log/exim4/mainlog
# Найти письмо по получателю:
grep "recipient@gmail.com" /var/log/exim4/mainlog | tail -20
# Панический лог (серьёзные ошибки конфига):
cat /var/log/exim4/paniclog
# Если этот файл не пустой — это первое что надо читать
</code></pre>
<h3>Тест отправки через Exim напрямую</h3>
<pre><code class="language-bash">
# Тест доставки конкретному адресу (без реальной отправки):
exim -bt recipient@gmail.com
# Покажет как Exim маршрутизирует письмо к этому адресу
# Отправить тестовое письмо из командной строки:
echo "Test body" | exim -v recipient@gmail.com
# Проверить статус конфигурации:
exim -bV 2>&1 | grep -E "version|support|Lookups"
# Проверить что Exim слушает нужные порты:
ss -tlnp | grep exim
</code></pre>
<hr />
<h2>Шаг 5 — DNS: SPF, DKIM, DMARC, PTR</h2>
<p>Это раздел который все пропускают. А потом удивляются, почему письма летят в спам или не доходят вообще. PTR нет — сервер анонимный, Gmail не любит анонимов. SPF не включает IP — письма от «самозванца». DKIM нет — подпись не верифицируется. DMARC нет — Microsoft начинает хмуриться.</p>
<h3>PTR-запись</h3>
<pre><code class="language-bash">
# Получить свой внешний IP:
curl -s https://api.ipify.org && echo
# Проверить PTR (замени 1.2.3.4 на свой IP):
dig -x 1.2.3.4 +short
# Должно вернуть: mail.yourdomain.com.
# Пусто = PTR не настроен = иди в панель провайдера и настраивай
# Или через nslookup:
nslookup 1.2.3.4
</code></pre>
<h3>SPF</h3>
<pre><code class="language-bash">
# Проверить SPF-запись:
dig TXT yourdomain.com +short | grep spf
# Должно быть: "v=spf1 ip4:1.2.3.4 include:... ~all"
# Если IP сервера не в SPF — Gmail и Outlook будут отбивать письма.
# Минимальная SPF-запись (добавь TXT в DNS):
# v=spf1 ip4:ТУТ_IP_ТВОЕГО_СЕРВЕРА mx ~all
</code></pre>
<h3>DKIM</h3>
<pre><code class="language-bash">
# Проверить DKIM-запись (селектор 'mail'):
dig TXT mail._domainkey.yourdomain.com +short
# Должна быть длинная строка с "p=" — это публичный ключ
# Если нет — ставим opendkim:
apt-get install -y opendkim opendkim-tools
# Генерируем ключи:
mkdir -p /etc/opendkim/keys/yourdomain.com
opendkim-genkey -b 2048 -d yourdomain.com \
-D /etc/opendkim/keys/yourdomain.com -s mail -v
# Смотрим что добавить в DNS:
cat /etc/opendkim/keys/yourdomain.com/mail.txt
# Права на приватный ключ:
chown opendkim:opendkim /etc/opendkim/keys/yourdomain.com/mail.private
chmod 600 /etc/opendkim/keys/yourdomain.com/mail.private
</code></pre>
<pre><code class="language-text">
# /etc/opendkim.conf — минимальный конфиг:
Domain yourdomain.com
KeyFile /etc/opendkim/keys/yourdomain.com/mail.private
Selector mail
Socket inet:12301@localhost
Mode sv
</code></pre>
<pre><code class="language-text">
# /etc/postfix/main.cf — подключить milter:
milter_protocol = 6
milter_default_action = accept
smtpd_milters = inet:localhost:12301
non_smtpd_milters = inet:localhost:12301
</code></pre>
<pre><code class="language-bash">
systemctl restart opendkim postfix
</code></pre>
<h3>DMARC</h3>
<pre><code class="language-bash">
# Проверить DMARC:
dig TXT _dmarc.yourdomain.com +short
# Ожидаем: "v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com"
# Минимальная запись (TXT на _dmarc.yourdomain.com):
# v=DMARC1; p=none; rua=mailto:postmaster@yourdomain.com
# p=none — только мониторинг. p=quarantine — спам. p=reject — жёсткий отказ.
# Начни с none, потом ужесточай.
</code></pre>
<table>
<thead>
<tr>
<th>Инструмент</th>
<th>Что проверяет</th>
<th>URL</th>
</tr>
</thead>
<tbody>
<tr>
<td>MXToolbox</td>
<td>SPF, DKIM, DMARC, Blacklist, MX</td>
<td>mxtoolbox.com</td>
</tr>
<tr>
<td>Mail-tester.com</td>
<td>Полный скоринг письма</td>
<td>mail-tester.com</td>
</tr>
<tr>
<td>DKIM Validator</td>
<td>DKIM-подпись</td>
<td>dkimvalidator.com</td>
</tr>
<tr>
<td>Google Postmaster</td>
<td>Репутация домена у Gmail</td>
<td>postmaster.google.com</td>
</tr>
</tbody>
</table>
<hr />
<h2>Шаг 6 — Проверка IP на blacklist</h2>
<pre><code class="language-bash">
# Быстрая проверка вручную (замени 1.2.3.4 на свой IP):
# Для Spamhaus:
dig 4.3.2.1.zen.spamhaus.org
# Для Spamcop:
dig 4.3.2.1.bl.spamcop.net
# 127.0.0.x в ответе = ты в списке. NXDOMAIN = чист.
</code></pre>
<pre><code class="language-bash">
#!/bin/bash
# Скрипт проверки по 6 blacklist-ам сразу:
IP="1.2.3.4" # Замени на свой IP
REVERSED=$(echo $IP | awk -F. '{print $4"."$3"."$2"."$1}')
LISTS=(
"zen.spamhaus.org"
"bl.spamcop.net"
"dnsbl.sorbs.net"
"b.barracudacentral.org"
"dnsbl-1.uceprotect.net"
"psbl.surriel.com"
)
echo "Проверка IP: $IP"
echo "-----------------------------"
for LIST in "${LISTS[@]}"; do
RESULT=$(dig +short "${REVERSED}.${LIST}" 2>/dev/null)
if [ -n "$RESULT" ]; then
echo "НАЙДЕН в: $LIST ($RESULT)"
else
echo "Чист: $LIST"
fi
done
</code></pre>
<p>IP в blacklist — подаёшь заявку на делистинг на сайте конкретного листа. Spamhaus: spamhaus.org/removal. Barracuda: lookup.barracudacentral.org. Spamcop: не делистирует сам, ждёшь 24 часа после прекращения жалоб.</p>
<hr />
<h2>Шаг 7 — Тест SMTP вручную: telnet и openssl</h2>
<p>Это самый надёжный способ убедиться что SMTP вообще работает. Руками, без обёрток.</p>
<h3>Telnet на порт 25</h3>
<pre><code class="language-bash">
telnet localhost 25
# После подключения — вводишь команды вручную:
</code></pre>
<pre><code class="language-text">
EHLO test.yourdomain.com
MAIL FROM:<test@yourdomain.com>
RCPT TO:<recipient@gmail.com>
DATA
Subject: Manual SMTP test
Test body — если это дошло, значит работает.
.
QUIT
</code></pre>
<h3>STARTTLS через openssl на порт 587</h3>
<pre><code class="language-bash">
# Подключиться с STARTTLS:
openssl s_client -starttls smtp -connect localhost:587
# К внешнему серверу:
openssl s_client -starttls smtp -connect smtp.gmail.com:587
# После подключения вводишь:
# EHLO yourdomain.com
# AUTH LOGIN
# (потом base64-логин и пароль отдельными строками)
# Закодировать логин/пароль в base64:
echo -n "user@yourdomain.com" | base64
echo -n "yourpassword" | base64
</code></pre>
<h3>SMTPS через openssl на порт 465</h3>
<pre><code class="language-bash">
openssl s_client -connect localhost:465
# Порт 465 — сразу SSL/TLS, без STARTTLS
# После подключения видишь баннер сервера
</code></pre>
<h3>swaks — лучший тестировщик SMTP</h3>
<p>Одна команда вместо двадцати. Тестирует всё включая аутентификацию и TLS.</p>
<pre><code class="language-bash">
# Тест с аутентификацией через порт 587:
swaks \
--to recipient@gmail.com \
--from sender@yourdomain.com \
--server localhost \
--port 587 \
--auth LOGIN \
--auth-user sender@yourdomain.com \
--auth-password "yourpassword" \
--tls \
--header "Subject: SMTP Test via swaks" \
--body "Если это дошло — сервер работает. Можно идти спать."
# Тест без авторизации (порт 25, локально):
swaks --to recipient@gmail.com --from sender@yourdomain.com --server localhost
# Тест с подробным выводом (для отладки):
swaks --to recipient@gmail.com --server localhost --port 587 -tlso --tls -v
</code></pre>
<hr />
<h2>Шаг 8 — Диагностика TLS/STARTTLS</h2>
<p>TLS не работает — и ты об этом не знаешь. Письма уходят или нет, но с ошибками в логах типа «STARTTLS not available» или «certificate verify failed». Разбираем отдельно.</p>
<h3>Проверить TLS на своём сервере</h3>
<pre><code class="language-bash">
# Проверить что Postfix поддерживает TLS:
postconf -a | grep -i tls
# или:
postconf smtpd_tls_security_level smtp_tls_security_level
# Посмотреть TLS-параметры в конфиге:
postconf | grep -E "tls|ssl" | grep -v "^#"
# Проверить сертификат:
openssl s_client -starttls smtp -connect localhost:587 2>/dev/null | \
openssl x509 -noout -dates -subject
# Смотрим: notBefore, notAfter (срок действия), subject (домен)
</code></pre>
<pre><code class="language-bash">
# Проверить срок сертификата — не истёк ли:
openssl s_client -starttls smtp -connect localhost:587 2>/dev/null | \
openssl x509 -noout -enddate
# Если дата в прошлом — сертификат истёк. Обнови.
# Для Let's Encrypt — проверить автообновление:
certbot renew --dry-run
# или:
systemctl status certbot.timer
</code></pre>
<h3>Настройка TLS в Postfix</h3>
<pre><code class="language-text">
# /etc/postfix/main.cf — параметры TLS:
# Входящие соединения (smtpd = сервер):
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.yourdomain.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.yourdomain.com/privkey.pem
smtpd_tls_security_level = may
# may = предлагать TLS, не требовать.
# encrypt = требовать TLS. Осторожно — может сломать старых клиентов.
# Исходящие соединения (smtp = клиент):
smtp_tls_security_level = may
smtp_tls_loglevel = 1
# loglevel=1 — логировать TLS-соединения. Помогает при отладке.
# Кэш TLS-сессий:
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
</code></pre>
<pre><code class="language-bash">
# Применить:
postfix check && systemctl reload postfix
# Проверить в логах что TLS поднимается:
grep -i "tls" /var/log/mail.log | tail -20
# Ищем: "TLS connection established" — хорошо.
# "STARTTLS not available" — TLS не поднялся, смотри конфиг.
# "certificate verify failed" — проблема с сертификатом.
</code></pre>
<h3>TLS в Exim</h3>
<pre><code class="language-bash">
# Проверить что Exim поддерживает TLS:
exim -bV | grep -i tls
# Ищем: Support for: ... TLS
# Проверить TLS-соединение к своему Exim:
openssl s_client -starttls smtp -connect localhost:587
# Логи TLS в Exim (включить если нет):
# В /etc/exim4/exim4.conf добавь в секцию main:
# log_selector = +tls_peerdn +tls_certificate_verified
# Применить:
systemctl reload exim4
grep -i tls /var/log/exim4/mainlog | tail -20
</code></pre>
<hr />
<h2>Шаг 9 — SMTP relay: SendGrid, Mailgun, Amazon SES</h2>
<p>Если порт 25 заблокирован провайдером и они не открывают — relay через внешний сервис. Это вообще правильнее для серьёзных рассылок: репутация IP у SendGrid уже наработана, доставляемость выше, blacklist не твоя проблема.</p>
<pre class="mermaid">%%{init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#ffffff',
'primaryTextColor': '#1e293b',
'primaryBorderColor': '#94a3b8',
'lineColor': '#64748b',
'fontSize': '15px',
'fontFamily': 'ui-sans-serif, system-ui, sans-serif'
},
'flowchart': {'curve': 'linear', 'nodeSpacing': 50, 'rankSpacing': 50}
}}%%
flowchart LR
APP["Postfix\nна твоём VPS"]
RELAY["SMTP Relay\nSendGrid / Mailgun / SES\nПорт 587"]
DEST["Получатель\nGmail / Outlook"]
APP -->|"Аутентификация\nAPI key / SASL"| RELAY
RELAY -->|"Проверенный IP\nВысокая репутация"| DEST
style APP fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#1e40af
style RELAY fill:#f8fafc,stroke:#f97316,stroke-width:2px,color:#c2410c
style DEST fill:#f8fafc,stroke:#22c55e,stroke-width:2px,color:#15803d
</pre>
<p><em>Схема 2: SMTP relay — Postfix отправляет через внешний сервис. Твой IP не важен, важна репутация relay-провайдера.</em></p>
<pre><code class="language-text">
# /etc/postfix/main.cf — relay через SendGrid:
relayhost = [smtp.sendgrid.net]: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
header_size_limit = 4096000
</code></pre>
<pre><code class="language-bash">
# Создать файл с паролями:
echo "[smtp.sendgrid.net]:587 apikey:ТУТ_ТВОЙ_API_KEY" > /etc/postfix/sasl_passwd
postmap /etc/postfix/sasl_passwd
chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
# Применить:
systemctl reload postfix
# Тест через swaks:
swaks --to test@gmail.com --from sender@yourdomain.com \
--server smtp.sendgrid.net --port 587 \
--auth-user apikey --auth-password "ТУТ_ТВОЙ_API_KEY" --tls
</code></pre>
<p><strong>Для Mailgun</strong> — замени хост на <code>smtp.mailgun.org</code> и используй SMTP credentials из панели. <strong>Для Amazon SES</strong> — <code>email-smtp.us-east-1.amazonaws.com:587</code>, credentials из IAM. Логика та же.</p>
<hr />
<h2>Коды ошибок SMTP: расшифровка</h2>
<p>В логах есть числа. Они не случайные. Вот что значат.</p>
<table>
<thead>
<tr>
<th>Код</th>
<th>Что означает</th>
<th>Первый шаг</th>
</tr>
</thead>
<tbody>
<tr>
<td>220</td>
<td>Сервер готов</td>
<td>Норма, соединение установлено</td>
</tr>
<tr>
<td>250</td>
<td>Команда принята</td>
<td>Норма</td>
</tr>
<tr>
<td>421</td>
<td>Сервис временно недоступен</td>
<td>Принимающий <a title="Настройка NTP на MikroTik: клиент и сервер — шпаргалка для ROS 6 и 7" href="https://it-apteka.com/nastrojka-ntp-na-mikrotik-klient-i-server-shpargalka-dlja-ros-6-i-7/" target="_blank" rel="noopener" data-wpil-monitor-id="1485">сервер перегружен —</a> deferred, попробует позже</td>
</tr>
<tr>
<td>450</td>
<td>Ящик временно недоступен</td>
<td>Временная ошибка, будет retry</td>
</tr>
<tr>
<td>451</td>
<td>Ошибка обработки на сервере</td>
<td>Проверь /etc/resolv.conf, DNS-резолвер</td>
</tr>
<tr>
<td>452</td>
<td>Недостаточно места</td>
<td>df -h <a title="DHCP Snooping — что это такое и как защитить сеть от Rogue DHCP сервера" href="https://it-apteka.com/dhcp-snooping-chto-jeto-takoe-i-kak-zashhitit-set-ot-rogue-dhcp-servera-2/" target="_blank" rel="noopener" data-wpil-monitor-id="1490">— проверь диск на сервере</a></td>
</tr>
<tr>
<td>500</td>
<td>Синтаксическая ошибка команды</td>
<td>Неверная команда в SMTP-сессии</td>
</tr>
<tr>
<td>501</td>
<td>Неверные параметры команды</td>
<td>Проверь формат <a class="wpil_keyword_link" title="mail" href="https://it-apteka.com/tag/mail/" target="_blank" rel="noopener" data-wpil-keyword-link="linked" data-wpil-monitor-id="1482">MAIL</a> FROM / RCPT TO</td>
</tr>
<tr>
<td>550</td>
<td>Ящик не найден / отказ доставки</td>
<td>Адрес не существует или заблокирован</td>
</tr>
<tr>
<td>550 5.7.1</td>
<td>SPF check failed</td>
<td>Добавь ip4:IP в SPF-запись домена</td>
</tr>
<tr>
<td>550 5.7.26</td>
<td>DMARC policy violation</td>
<td>Проверь SPF+DKIM, оба должны пройти</td>
</tr>
<tr>
<td>553</td>
<td>Неверный адрес отправителя</td>
<td>Проверь myhostname и myorigin в main.cf</td>
</tr>
<tr>
<td>554</td>
<td>Transaction failed</td>
<td>IP в blacklist или письмо содержит спам-контент</td>
</tr>
<tr>
<td>535</td>
<td>Authentication failed</td>
<td><a title="Почему Proxmox неверно отображает расход памяти Windows 7, 10, 11 — решение проблемы" href="https://it-apteka.com/pochemu-proxmox-neverno-otobrazhaet-rashod-pamjati-windows-7-10-11-reshenie-problemy/" target="_blank" rel="noopener" data-wpil-monitor-id="1492">Неверный логин/пароль —</a> проверь sasl_passwd</td>
</tr>
<tr>
<td>534</td>
<td>Authentication mechanism too weak</td>
<td>Включи STARTTLS <a title="SSH-ключи: подключение без пароля — полный гайд для Linux, Windows и macOS" href="https://it-apteka.com/ssh-kljuchi-podkljuchaemsja-bez-parolja-i-ne-panikuem/" target="_blank" rel="noopener" data-wpil-monitor-id="1484">— сервер не принимает пароли</a> без шифрования</td>
</tr>
</tbody>
</table>
<h3>Типовые сообщения из логов</h3>
<table>
<thead>
<tr>
<th>Ошибка в логах</th>
<th>Причина</th>
<th>Решение</th>
</tr>
</thead>
<tbody>
<tr>
<td>relay access denied</td>
<td>Postfix не пускает как relay без авторизации</td>
<td>Настрой SASL auth, проверь mynetworks</td>
</tr>
<tr>
<td>Connection refused (port 25)</td>
<td>MTA не слушает или провайдер режет</td>
<td>systemctl status postfix, тикет провайдеру</td>
</tr>
<tr>
<td>Connection timed out</td>
<td>Файрвол режет исходящие соединения</td>
<td>Проверь iptables/ufw, попробуй relay</td>
</tr>
<tr>
<td>SASL authentication failed</td>
<td>Неверный логин/пароль для relay</td>
<td>Проверь sasl_passwd, пересоздай postmap</td>
</tr>
<tr>
<td>mail for X loops back to myself</td>
<td>Неверный mydestination или myhostname</td>
<td>Убери домен из mydestination</td>
</tr>
<tr>
<td>STARTTLS not available</td>
<td>TLS не настроен или сертификат недействителен</td>
<td>Проверь cert_file/key_file в main.cf</td>
</tr>
<tr>
<td>certificate verify failed</td>
<td>Сертификат истёк или самоподписанный</td>
<td>certbot renew, проверь дату сертификата</td>
</tr>
<tr>
<td>deferred (host or domain not found)</td>
<td>DNS не резолвит MX получателя</td>
<td>Проверь /etc/resolv.conf, смени DNS на 8.8.8.8</td>
</tr>
<tr>
<td>fatal: open /etc/postfix/main.cf: Permission denied</td>
<td>Права на конфиг сломаны</td>
<td>chown root:root /etc/postfix/main.cf, chmod 644</td>
</tr>
<tr>
<td>warning: SASL: Connect to private/auth failed</td>
<td>Dovecot не запущен или сокет не там</td>
<td>systemctl status dovecot, проверь smtpd_sasl_path</td>
</tr>
</tbody>
</table>
<hr />
<h2>Скрипт автодиагностики SMTP</h2>
<p>Хватит делать всё по одному. Скрипт пробегается по всем ключевым точкам и выдаёт отчёт за 30 секунд. Скопируй, сохрани, запусти.</p>
<pre><code class="language-bash">
#!/bin/bash
# ================================================
# smtp_diag.sh — Диагностика SMTP-сервера Linux
# Использование: sudo bash smtp_diag.sh yourdomain.com 1.2.3.4
# ================================================
DOMAIN="${1:-yourdomain.com}"
SERVER_IP="${2:-$(curl -s https://api.ipify.org 2>/dev/null)}"
REVERSED_IP=$(echo "$SERVER_IP" | awk -F. '{print $4"."$3"."$2"."$1}')
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
ok() { echo -e "${GREEN}OK ${NC} $1"; }
fail() { echo -e "${RED}FAIL ${NC} $1"; }
warn() { echo -e "${YELLOW}WARN ${NC} $1"; }
echo "========================================"
echo " SMTP Диагностика | IT-Apteka.com"
echo " Домен: $DOMAIN | IP: $SERVER_IP"
echo "========================================"
# 1. MTA
echo; echo "[ 1/8 ] Почтовый агент (MTA)"
MTA_FOUND=0
for MTA in postfix exim4 exim sendmail; do
if systemctl is-active --quiet "$MTA" 2>/dev/null; then
ok "$MTA запущен"
MTA_FOUND=1; break
fi
done
[ $MTA_FOUND -eq 0 ] && fail "Ни один MTA не запущен (postfix/exim/sendmail)"
# 2. Порты
echo; echo "[ 2/8 ] Порты SMTP (локально)"
for PORT in 25 587 465; do
if ss -tlnp | grep -q ":$PORT "; then
ok "Порт $PORT слушает"
else
warn "Порт $PORT не слушает"
fi
done
# 3. Исходящий порт 25
echo; echo "[ 3/8 ] Исходящий порт 25 (к Google MX)"
if timeout 8 bash -c 'echo QUIT | telnet aspmx.l.google.com 25 2>&1' | grep -q "220"; then
ok "Исходящий порт 25 открыт"
else
fail "Исходящий порт 25 заблокирован — провайдер или файрвол"
fi
# 4. PTR
echo; echo "[ 4/8 ] PTR-запись (обратный DNS)"
PTR=$(dig -x "$SERVER_IP" +short 2>/dev/null | head -1)
if [ -n "$PTR" ]; then
ok "PTR настроен: $PTR"
else
fail "PTR-запись отсутствует для IP $SERVER_IP"
fi
# 5. SPF
echo; echo "[ 5/8 ] SPF-запись"
SPF=$(dig TXT "$DOMAIN" +short 2>/dev/null | grep -i "v=spf1")
if [ -n "$SPF" ]; then
ok "SPF найден: $SPF"
echo "$SPF" | grep -q "$SERVER_IP" && \
ok "IP сервера включён в SPF" || \
warn "IP $SERVER_IP может не быть в SPF — проверь вручную"
else
fail "SPF-запись отсутствует для $DOMAIN"
fi
# 6. DKIM
echo; echo "[ 6/8 ] DKIM (селектор 'mail')"
DKIM=$(dig TXT "mail._domainkey.$DOMAIN" +short 2>/dev/null)
if [ -n "$DKIM" ]; then
ok "DKIM-запись найдена"
else
fail "DKIM не найден (mail._domainkey.$DOMAIN)"
fi
# 7. DMARC
echo; echo "[ 7/8 ] DMARC"
DMARC=$(dig TXT "_dmarc.$DOMAIN" +short 2>/dev/null | grep -i "v=DMARC1")
if [ -n "$DMARC" ]; then
ok "DMARC найден: $DMARC"
else
warn "DMARC-запись отсутствует (не критично, но желательно)"
fi
# 8. Blacklist
echo; echo "[ 8/8 ] Blacklist"
LISTS=("zen.spamhaus.org" "bl.spamcop.net" "dnsbl.sorbs.net" "b.barracudacentral.org")
for LIST in "${LISTS[@]}"; do
RESULT=$(dig +short "${REVERSED_IP}.${LIST}" 2>/dev/null)
[ -n "$RESULT" ] && fail "IP найден в $LIST ($RESULT)" || ok "Чист: $LIST"
done
echo; echo "========================================"
echo " Готово. Домен: $DOMAIN | IP: $SERVER_IP"
echo " $(date)"
echo "========================================"
</code></pre>
<pre><code class="language-bash">
# Сохранить и запустить:
chmod +x smtp_diag.sh
sudo bash smtp_diag.sh yourdomain.com 1.2.3.4
</code></pre>
<hr />
<h2>Осложнения: чек-лист последней надежды</h2>
<p>Прошёл все шаги, всё зелёное, а письма всё равно не уходят. Одна капля никотина убивает лошадь. Одна строчка в main.cf без перезагрузки — всю диагностику.</p>
<p><strong>Проверить hostname.</strong> Должен совпадать с PTR-записью, быть FQDN.</p>
<pre><code class="language-bash">
hostname -f
# Должно быть: mail.yourdomain.com
# Не так — исправь в /etc/hostname и /etc/hosts, потом hostname -F /etc/hostname
</code></pre>
<p><strong>Проверить диск.</strong> Postfix молча падает при 100% заполнении.</p>
<pre><code class="language-bash">
df -h
# /var или / под завязку — чисти
du -sh /var/spool/postfix/deferred/
du -sh /var/log/
# Ротировать логи:
logrotate -f /etc/logrotate.d/rsyslog
</code></pre>
<p><strong>SELinux / AppArmor на пути.</strong></p>
<pre><code class="language-bash">
# SELinux:
getenforce
# Enforcing — попробуй временно:
setenforce 0
# Смотреть что блокирует:
grep postfix /var/log/audit/audit.log | grep denied | tail -20
# AppArmor:
aa-status | grep postfix
</code></pre>
<p><strong>Права на директории Postfix.</strong></p>
<pre><code class="language-bash">
postfix set-permissions
ls -la /var/spool/postfix/
</code></pre>
<p><strong>Конфиг прошёл check, но не перезагружен.</strong></p>
<pre><code class="language-bash">
postfix check && systemctl reload postfix
# reload — применяет main.cf без разрыва соединений
# restart — полный перезапуск, если reload не помог
</code></pre>
<p><strong>Gmail отбивает конкретно твой домен.</strong> Зарегистрируй домен в Google Postmaster Tools — там видна репутация и причины блокировок: postmaster.google.com</p>
<p><strong>Outlook / Microsoft блокирует.</strong> Подай заявку через Sender Support: sendersupport.olc.protection.outlook.com</p>
<hr />
<h2>Профилактика: как не получить это в следующий раз</h2>
<p><a title="Запуск bash скриптов в Linux: через терминал, cron, Python, Windows и Raspberry Pi" href="https://it-apteka.com/zapusk-bash-skriptov-v-linux-cherez-terminal-cron-python-windows-i-raspberry-pi/" target="_blank" rel="noopener" data-wpil-monitor-id="1487">Скрипт мониторинга очереди — добавь в cron</a>, он пришлёт алерт если что-то пошло не так:</p>
<pre><code class="language-bash">
#!/bin/bash
# /usr/local/bin/check_mailq.sh
# Crontab: */15 * * * * /usr/local/bin/check_mailq.sh
THRESHOLD=100
ADMIN_EMAIL="admin@yourdomain.com"
QUEUE_SIZE=$(postqueue -p 2>/dev/null | tail -1 | grep -oP '^\d+')
if [ -n "$QUEUE_SIZE" ] && [ "$QUEUE_SIZE" -gt "$THRESHOLD" ]; then
echo "ALERT: В очереди Postfix $QUEUE_SIZE писем на $(hostname) в $(date)" \
| mail -s "Postfix queue alert" "$ADMIN_EMAIL"
fi
</code></pre>
<pre><code class="language-bash">
chmod +x /usr/local/bin/check_mailq.sh
(crontab -l 2>/dev/null; echo "*/15 * * * * /usr/local/bin/check_mailq.sh") | crontab -
</code></pre>
<p>Три правила которые избавят от большинства проблем: <a class="wpil_keyword_link" title="Мониторинг" href="https://it-apteka.com/category/monitoring/" target="_blank" rel="noopener" data-wpil-keyword-link="linked" data-wpil-monitor-id="1481">мониторинг</a> очереди раз в 15 минут, проверка blacklist раз в неделю через MXToolbox, и никогда не запускать массовые рассылки прямо с боевого сервера. Для рассылок — отдельный IP или внешний сервис. Репутация IP нарабатывается месяцами, сжигается за час.</p>
<hr />
<h2>FAQ: вопросы про диагностику SMTP на Linux</h2>
<h3>Почему письма уходят в спам а не во входящие?</h3>
<p>Почти всегда одна из трёх причин: IP в blacklist, SPF не включает IP сервера, или DKIM не настроен. Проверяй в таком порядке: <a class="wpil_keyword_link" title="Скрипты" href="https://it-apteka.com/category/scripts/" target="_blank" rel="noopener" data-wpil-keyword-link="linked" data-wpil-monitor-id="1491">скрипт</a> blacklist-проверки → <code>dig TXT домен +short | grep spf</code> → <code>dig TXT mail._domainkey.домен +short</code>. Если всё три ок — проверь mail-tester.com, он покажет скоринг и конкретные причины.</p>
<h3>Как понять что именно Postfix пишет в deferred и почему не отправляет?</h3>
<pre><code class="language-bash">
# Посмотреть причину deferred для каждого письма:
postqueue -p | grep "^[A-F0-9]" | while read id rest; do
echo "=== $id ==="
postcat -q "$id" 2>/dev/null | grep -E "reason|error|host|status"
done
# Или прямо из логов — причина всегда рядом с "deferred":
grep "deferred" /var/log/mail.log | tail -20
</code></pre>
<h3>Что делать если провайдер не открывает порт 25?</h3>
<p>Переходи на SMTP relay через порт 587. SendGrid даёт 100 писем в день бесплатно, Mailgun — 1000 в месяц, Amazon SES <a title="VPN на MikroTik: полный гайд 2026 — WireGuard, L2TP/IPsec, IKEv2, настройка сервера и клиента" href="https://it-apteka.com/vpn-na-mikrotik-polnyj-gajd-2026-wireguard-l2tp-ipsec-ikev2-nastrojka-servera-i-klienta/" target="_blank" rel="noopener" data-wpil-monitor-id="1493">— 62000 в месяц если сервер</a> на EC2. Настройка занимает 20 минут по инструкции выше. Это вообще правильнее для боевого сервера: не надо следить за репутацией IP, доставляемость выше.</p>
<h3>Как проверить что DKIM-подпись валидна?</h3>
<pre><code class="language-bash">
# Отправить письмо на check-auth@verifier.port25.com:
echo "Test" | mail -s "DKIM test" check-auth@verifier.port25.com
# Через минуту придёт автоответ с результатами проверки SPF/DKIM/DMARC
# Или через swaks и потом проверить заголовки полученного письма:
swaks --to check-auth@verifier.port25.com --from test@yourdomain.com --server localhost
</code></pre>
<h3>Exim или Postfix — что выбрать для нового сервера?</h3>
<p>На новом сервере — Postfix. Проще конфиг, лучше документация, большинство туториалов под него. Exim стоит по умолчанию на Debian и на хостингах с cPanel — там не выбираешь. Если уже стоит Exim и работает — не трогай без причины.</p>
<hr />
<h2>Итог</h2>
<p><a title="DIG: продвинутая диагностика DNS для Linux и Windows" href="https://it-apteka.com/dig-shpargalka-it-inzhenera-s-primerami/" target="_blank" rel="noopener" data-wpil-monitor-id="1488">Диагностика SMTP-сервера на Linux</a> — это последовательность из восьми проверок, не гадание на кофейной гуще. MTA запущен, порт открыт, DNS настроен, IP чист, TLS работает. Каждый пункт — одна команда, результат — сразу.</p>
<p>Если после всего этого письма всё равно не уходят — переходи на SMTP relay. Это не поражение, это правильное решение для большинства VPS где провайдер режет 25-й порт и не собирается его открывать.</p>
"Не
<br />
Если прошли весь чек-лист и получили нестандартный код ошибки — пишите. Разберём. Подписывайтесь на телеграм IT-Apteka <a title="Windows 12 — дата выхода, версии, 64 bit и что известно в 2026 году" href="https://it-apteka.com/windows-12-data-vyhoda-versii-64-bit-i-chto-izvestno-v-2026-godu/" target="_blank" rel="noopener" data-wpil-monitor-id="1494">— туда выходят</a> новые рецепты без воды.<br />
Быстрый ответ
Письма не уходят с Linux-сервера в 80% случаев по одной из трёх причин: провайдер заблокировал порт 25, IP не в SPF-записи, или MTA вообще не запущен. Проверяй в таком порядке: systemctl status postfix → telnet aspmx.l.google.com 25 → dig TXT домен +short | grep spf. Если всё три ок — читай дальше, там глубже.
Диагноз: сервер молчит, письма не уходят, клиент уже пишет
Настроил рассылку. Или форму обратной связи. Или переехал на новый VPS. И тишина. В логах — «deferred», «relay access denied», «connection refused». Клиент пишет что не получил письмо. Дедлайн через час.
Знакомо. Видел это раз триста. И каждый раз причина одна из пяти — просто не всегда очевидно, которая именно.
Вот что получишь после прочтения: понимание почему вообще это ломается, пошаговую диагностику с командами copy-paste, отдельные разделы для Postfix и Exim, разбор SMTP-кодов ошибок, диагностику TLS/STARTTLS, настройку relay через внешние сервисы и скрипт автодиагностики. Времени: 15 минут если проблема типовая, 40 — если всё плохо.
Что нужно: root или sudo на сервере, пара утилит и нежелание гуглить каждую ошибку отдельно.
# Установить всё нужное сразу:
# Debian/Ubuntu:
apt-get install -y telnet openssl mailutils dnsutils curl swaks
# CentOS/RHEL/Rocky:
yum install -y telnet openssl mailx bind-utils curl
# swaks отдельно (нет в базовых репах):
curl -L https://jetmore.org/john/code/swaks/files/swaks -o /usr/local/bin/swaks
chmod +x /usr/local/bin/swaks
Пять причин — и одна из них твоя
Перед тем как лезть в конфиги — обозначим врага. Проблемы с отправкой почты с Linux-сервера делятся ровно на пять групп. Почти всегда это одна из них.
1. Заблокирован порт 25 провайдером. Самая частая причина на новых VPS. AWS, Hetzner, DigitalOcean, Selectel — все по умолчанию режут исходящий порт 25 против спама. Твой Postfix исправно пытается отправить, а на уровне сети его уже нет. Решение: либо тикет провайдеру, либо SMTP relay через порт 587.
2. MTA не запущен или сломан конфиг. Postfix упал тихо ночью. Exim не слушает нужный интерфейс. Конфиг сломался после apt upgrade. Очередь переполнена и заморожена. Смешно, но 20% случаев — именно это.
3. DNS: SPF, DKIM, DMARC, PTR. Письмо уходит с сервера, но Gmail его отбивает или кидает в спам. IP не включён в SPF. DKIM-подписи нет. PTR-записи нет — сервер «анонимный», и это красный флаг для всех серьёзных почтовых систем.
4. IP в чёрном списке. Предыдущий арендатор VPS с этого IP рассылал спам. Или ты сам случайно отправил тысячу писем в цикле. Теперь IP в DNSBL — письма молча отбиваются без объяснений.
5. Проблема аутентификации SMTP. SASL auth не настроен. TLS не работает. Приложение пытается подключиться без авторизации, а relay запрещён. Итог: «relay access denied» или «authentication required».
Правило экономии времени
В 80% случаев виноваты пункты 1 и 3. Начни с них — сэкономишь час жизни.
Как работает путь письма: схема
Прежде чем диагностировать — пойми где именно рвётся цепочка. Каждый узел может быть точкой отказа.
%%{init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#ffffff',
'primaryTextColor': '#1e293b',
'primaryBorderColor': '#94a3b8',
'lineColor': '#64748b',
'fontSize': '15px',
'fontFamily': 'ui-sans-serif, system-ui, sans-serif'
},
'flowchart': {'curve': 'linear', 'nodeSpacing': 45, 'rankSpacing': 50}
}}%%
flowchart TD
APP["Приложение / PHP mail()\nSendmail / CLI"]
MTA["MTA (Postfix / Exim)\nОчередь отправки"]
PORT["Порт 25 / 587\nФайрвол / Провайдер"]
DNS_LOOKUP["DNS lookup\nMX-запись получателя"]
REMOTE["Принимающий SMTP\nGmail / Outlook / etc"]
SPAM_CHK["Проверки на приёмной стороне\nSPF / DKIM / DMARC / Blacklist"]
INBOX["Входящие получателя"]
SPAM["Спам / Отказ\n550 / 421 / deferred"]
APP -->|"sendmail() / SMTP"| MTA
MTA -->|"Очередь → отправка"| PORT
PORT -->|"TCP соединение"| DNS_LOOKUP
DNS_LOOKUP -->|"Резолв MX"| REMOTE
REMOTE -->|"Проверка отправителя"| SPAM_CHK
SPAM_CHK -->|"Прошёл"| INBOX
SPAM_CHK -->|"Не прошёл"| SPAM
style APP fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#1e40af
style MTA fill:#f8fafc,stroke:#f97316,stroke-width:2px,color:#c2410c
style PORT fill:#f8fafc,stroke:#ef4444,stroke-width:2px,color:#b91c1c
style DNS_LOOKUP fill:#f8fafc,stroke:#94a3b8,stroke-width:2px,color:#1e293b
style REMOTE fill:#f8fafc,stroke:#94a3b8,stroke-width:2px,color:#1e293b
style SPAM_CHK fill:#f8fafc,stroke:#f97316,stroke-width:2px,color:#c2410c
style INBOX fill:#f8fafc,stroke:#22c55e,stroke-width:2px,color:#15803d
style SPAM fill:#f8fafc,stroke:#ef4444,stroke-width:2px,color:#b91c1c
Схема 1: Путь письма от приложения до входящих. Каждый узел — потенциальная точка отказа. Диагностику начинай с MTA и PORT — там рвётся чаще всего.
Шаг 1 — Проверить запущен ли MTA
Смешно, но с этого надо начинать. Postfix падает тихо. После apt upgrade конфиг может не загрузиться. После перезагрузки сервера — не запуститься автоматически, если кто-то забыл enable.
Postfix
# Статус:
systemctl status postfix
# Ищи: Active: active (running)
# Если нет:
systemctl start postfix
systemctl enable postfix
# Проверить конфиг перед запуском:
postfix check
# Тихо = конфиг ок. Ошибки — будут выведены.
# Посмотреть на каком порту и интерфейсе слушает:
ss -tlnp | grep -E ':(25|587|465)'
# Должно быть: LISTEN 0 100 0.0.0.0:25 ...
Exim
# Статус (Debian/Ubuntu — exim4, CentOS — exim):
systemctl status exim4
systemctl status exim
# Запустить если не работает:
systemctl start exim4
systemctl enable exim4
# Проверить конфиг Exim:
exim -bV
# Покажет версию и список встроенных модулей
# Синтаксис конфига:
exim -C /etc/exim4/exim4.conf.template -bV 2>&1 | grep -i error
Если ss -tlnp | grep ':25' возвращает пустоту — MTA не слушает порт. Либо не запущен, либо в конфиге inet_interfaces настроен не так.
Шаг 2 — Проверить порты
Порт 25 — классика, которую режут все подряд. AWS, Hetzner, DigitalOcean блокируют исходящий 25 по умолчанию. Узнать это можно только попробовав.
# Проверить исходящий порт 25 с сервера (к MX Google):
telnet aspmx.l.google.com 25
# "Connected to aspmx.l.google.com" + баннер "220" = порт открыт
# Timeout или "Connection refused" = провайдер режет
# Без интерактива:
timeout 10 bash -c 'echo QUIT | telnet aspmx.l.google.com 25 2>&1' | grep -E "220|refused|timeout"
# Альтернатива через curl:
curl -v telnet://aspmx.l.google.com:25 2>&1 | head -15
# Проверить порт 587 (submission):
telnet localhost 587
telnet smtp.gmail.com 587
# Проверить порт 465 (SMTPS):
openssl s_client -connect localhost:465
# Посмотреть файрвол на сервере:
# UFW:
ufw status verbose
# iptables:
iptables -L -n | grep -E "smtp|25|587|465"
# firewalld:
firewall-cmd --list-all
Порт 25 заблокирован провайдером — что делать
Открой тикет провайдеру — объясни что ты легальный отправитель. Или сразу переходи на SMTP relay через порт 587. Для большинства задач это правильнее: не надо следить за репутацией IP, не надо бороться с blacklist-ами.
Шаг 3 — Диагностика Postfix: очередь и логи
Просмотр очереди
# Вся очередь:
mailq
# или:
postqueue -p
# Сколько писем застряло:
postqueue -p | tail -1
# Детали конкретного письма по ID из mailq:
postcat -q ABCDEF1234
# Принудительно отправить всё из очереди:
postqueue -f
# Удалить все письма (осторожно — необратимо):
postsuper -d ALL
# Удалить только deferred:
postsuper -d ALL deferred
# Удалить письма конкретного отправителя:
mailq | grep "^[A-F0-9]" | awk '{print $1}' | \
xargs -I{} postcat -q {} | grep -l "sender@example.com" | \
xargs postsuper -d
Логи Postfix
# Последние 100 строк:
tail -100 /var/log/mail.log
# На CentOS/Rocky:
tail -100 /var/log/maillog
# Только ошибки:
grep -iE "error|reject|deferred|bounced|failed|refused" /var/log/mail.log | tail -50
# Следить в реальном времени (пока тестируешь):
tail -f /var/log/mail.log
# Что происходило с конкретным письмом (по адресу получателя):
grep "recipient@gmail.com" /var/log/mail.log | tail -20
# Все попытки отправки за последний час:
grep "$(date '+%b %e %H')" /var/log/mail.log | grep "status="
Минимальный рабочий конфиг Postfix
Если хочешь начать с чистого листа — вот конфиг, который работает на большинстве серверов без сюрпризов:
# /etc/postfix/main.cf
myhostname = mail.yourdomain.com
mydomain = yourdomain.com
myorigin = $mydomain
inet_interfaces = all
inet_protocols = ipv4
# Локальная доставка — убери домен если не принимаешь почту на этот сервер:
mydestination = $myhostname, localhost.$mydomain, localhost
# Только локальные клиенты без авторизации:
mynetworks = 127.0.0.0/8
# Размер письма 50MB:
message_size_limit = 52428800
# TLS:
smtpd_tls_cert_file = /etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file = /etc/ssl/private/ssl-cert-snakeoil.key
smtpd_tls_security_level = may
smtp_tls_security_level = may
# SASL auth:
smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_security_options = noanonymous
# Ограничения:
smtpd_recipient_restrictions =
permit_sasl_authenticated,
permit_mynetworks,
reject_unauth_destination
# Применить конфиг:
postfix check && systemctl reload postfix
Шаг 4 — Диагностика Exim: очередь, логи, конфиг
Exim стоит по умолчанию на Debian и многих хостингах. Логика та же — очередь, логи, конфиг — но команды другие. Смешивать с Postfix не надо: либо одно, либо другое.
Очередь Exim
# Список писем в очереди:
exim -bp
# Количество писем:
exim -bpc
# Принудительно отправить все (включая frozen):
exim -qff
# Детали конкретного письма по ID:
exim -Mvl ИДЕНТИФИКАТОР
# Заголовки:
exim -Mvh ИДЕНТИФИКАТОР
# Тело:
exim -Mvb ИДЕНТИФИКАТОР
# Удалить конкретное письмо:
exim -Mrm ИДЕНТИФИКАТОР
# Удалить все замороженные (frozen):
exiqgrep -iz | xargs exim -Mrm
# Удалить всё из очереди:
exiqgrep -i | xargs exim -Mrm
Логи Exim
# Основной лог:
tail -100 /var/log/exim4/mainlog
# Только ошибки:
grep -iE "fail|reject|error|frozen|bounce" /var/log/exim4/mainlog | tail -50
# Следить в реальном времени:
tail -f /var/log/exim4/mainlog
# Найти письмо по получателю:
grep "recipient@gmail.com" /var/log/exim4/mainlog | tail -20
# Панический лог (серьёзные ошибки конфига):
cat /var/log/exim4/paniclog
# Если этот файл не пустой — это первое что надо читать
Тест отправки через Exim напрямую
# Тест доставки конкретному адресу (без реальной отправки):
exim -bt recipient@gmail.com
# Покажет как Exim маршрутизирует письмо к этому адресу
# Отправить тестовое письмо из командной строки:
echo "Test body" | exim -v recipient@gmail.com
# Проверить статус конфигурации:
exim -bV 2>&1 | grep -E "version|support|Lookups"
# Проверить что Exim слушает нужные порты:
ss -tlnp | grep exim
Шаг 5 — DNS: SPF, DKIM, DMARC, PTR
Это раздел который все пропускают. А потом удивляются, почему письма летят в спам или не доходят вообще. PTR нет — сервер анонимный, Gmail не любит анонимов. SPF не включает IP — письма от «самозванца». DKIM нет — подпись не верифицируется. DMARC нет — Microsoft начинает хмуриться.
PTR-запись
# Получить свой внешний IP:
curl -s https://api.ipify.org && echo
# Проверить PTR (замени 1.2.3.4 на свой IP):
dig -x 1.2.3.4 +short
# Должно вернуть: mail.yourdomain.com.
# Пусто = PTR не настроен = иди в панель провайдера и настраивай
# Или через nslookup:
nslookup 1.2.3.4
SPF
# Проверить SPF-запись:
dig TXT yourdomain.com +short | grep spf
# Должно быть: "v=spf1 ip4:1.2.3.4 include:... ~all"
# Если IP сервера не в SPF — Gmail и Outlook будут отбивать письма.
# Минимальная SPF-запись (добавь TXT в DNS):
# v=spf1 ip4:ТУТ_IP_ТВОЕГО_СЕРВЕРА mx ~all
DKIM
# Проверить DKIM-запись (селектор 'mail'):
dig TXT mail._domainkey.yourdomain.com +short
# Должна быть длинная строка с "p=" — это публичный ключ
# Если нет — ставим opendkim:
apt-get install -y opendkim opendkim-tools
# Генерируем ключи:
mkdir -p /etc/opendkim/keys/yourdomain.com
opendkim-genkey -b 2048 -d yourdomain.com \
-D /etc/opendkim/keys/yourdomain.com -s mail -v
# Смотрим что добавить в DNS:
cat /etc/opendkim/keys/yourdomain.com/mail.txt
# Права на приватный ключ:
chown opendkim:opendkim /etc/opendkim/keys/yourdomain.com/mail.private
chmod 600 /etc/opendkim/keys/yourdomain.com/mail.private
# /etc/opendkim.conf — минимальный конфиг:
Domain yourdomain.com
KeyFile /etc/opendkim/keys/yourdomain.com/mail.private
Selector mail
Socket inet:12301@localhost
Mode sv
# /etc/postfix/main.cf — подключить milter:
milter_protocol = 6
milter_default_action = accept
smtpd_milters = inet:localhost:12301
non_smtpd_milters = inet:localhost:12301
systemctl restart opendkim postfix
DMARC
# Проверить DMARC:
dig TXT _dmarc.yourdomain.com +short
# Ожидаем: "v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com"
# Минимальная запись (TXT на _dmarc.yourdomain.com):
# v=DMARC1; p=none; rua=mailto:postmaster@yourdomain.com
# p=none — только мониторинг. p=quarantine — спам. p=reject — жёсткий отказ.
# Начни с none, потом ужесточай.
| Инструмент |
Что проверяет |
URL |
| MXToolbox |
SPF, DKIM, DMARC, Blacklist, MX |
mxtoolbox.com |
| Mail-tester.com |
Полный скоринг письма |
mail-tester.com |
| DKIM Validator |
DKIM-подпись |
dkimvalidator.com |
| Google Postmaster |
Репутация домена у Gmail |
postmaster.google.com |
Шаг 6 — Проверка IP на blacklist
# Быстрая проверка вручную (замени 1.2.3.4 на свой IP):
# Для Spamhaus:
dig 4.3.2.1.zen.spamhaus.org
# Для Spamcop:
dig 4.3.2.1.bl.spamcop.net
# 127.0.0.x в ответе = ты в списке. NXDOMAIN = чист.
#!/bin/bash
# Скрипт проверки по 6 blacklist-ам сразу:
IP="1.2.3.4" # Замени на свой IP
REVERSED=$(echo $IP | awk -F. '{print $4"."$3"."$2"."$1}')
LISTS=(
"zen.spamhaus.org"
"bl.spamcop.net"
"dnsbl.sorbs.net"
"b.barracudacentral.org"
"dnsbl-1.uceprotect.net"
"psbl.surriel.com"
)
echo "Проверка IP: $IP"
echo "-----------------------------"
for LIST in "${LISTS[@]}"; do
RESULT=$(dig +short "${REVERSED}.${LIST}" 2>/dev/null)
if [ -n "$RESULT" ]; then
echo "НАЙДЕН в: $LIST ($RESULT)"
else
echo "Чист: $LIST"
fi
done
IP в blacklist — подаёшь заявку на делистинг на сайте конкретного листа. Spamhaus: spamhaus.org/removal. Barracuda: lookup.barracudacentral.org. Spamcop: не делистирует сам, ждёшь 24 часа после прекращения жалоб.
Шаг 7 — Тест SMTP вручную: telnet и openssl
Это самый надёжный способ убедиться что SMTP вообще работает. Руками, без обёрток.
Telnet на порт 25
telnet localhost 25
# После подключения — вводишь команды вручную:
EHLO test.yourdomain.com
MAIL FROM:<test@yourdomain.com>
RCPT TO:<recipient@gmail.com>
DATA
Subject: Manual SMTP test
Test body — если это дошло, значит работает.
.
QUIT
STARTTLS через openssl на порт 587
# Подключиться с STARTTLS:
openssl s_client -starttls smtp -connect localhost:587
# К внешнему серверу:
openssl s_client -starttls smtp -connect smtp.gmail.com:587
# После подключения вводишь:
# EHLO yourdomain.com
# AUTH LOGIN
# (потом base64-логин и пароль отдельными строками)
# Закодировать логин/пароль в base64:
echo -n "user@yourdomain.com" | base64
echo -n "yourpassword" | base64
SMTPS через openssl на порт 465
openssl s_client -connect localhost:465
# Порт 465 — сразу SSL/TLS, без STARTTLS
# После подключения видишь баннер сервера
swaks — лучший тестировщик SMTP
Одна команда вместо двадцати. Тестирует всё включая аутентификацию и TLS.
# Тест с аутентификацией через порт 587:
swaks \
--to recipient@gmail.com \
--from sender@yourdomain.com \
--server localhost \
--port 587 \
--auth LOGIN \
--auth-user sender@yourdomain.com \
--auth-password "yourpassword" \
--tls \
--header "Subject: SMTP Test via swaks" \
--body "Если это дошло — сервер работает. Можно идти спать."
# Тест без авторизации (порт 25, локально):
swaks --to recipient@gmail.com --from sender@yourdomain.com --server localhost
# Тест с подробным выводом (для отладки):
swaks --to recipient@gmail.com --server localhost --port 587 -tlso --tls -v
Шаг 8 — Диагностика TLS/STARTTLS
TLS не работает — и ты об этом не знаешь. Письма уходят или нет, но с ошибками в логах типа «STARTTLS not available» или «certificate verify failed». Разбираем отдельно.
Проверить TLS на своём сервере
# Проверить что Postfix поддерживает TLS:
postconf -a | grep -i tls
# или:
postconf smtpd_tls_security_level smtp_tls_security_level
# Посмотреть TLS-параметры в конфиге:
postconf | grep -E "tls|ssl" | grep -v "^#"
# Проверить сертификат:
openssl s_client -starttls smtp -connect localhost:587 2>/dev/null | \
openssl x509 -noout -dates -subject
# Смотрим: notBefore, notAfter (срок действия), subject (домен)
# Проверить срок сертификата — не истёк ли:
openssl s_client -starttls smtp -connect localhost:587 2>/dev/null | \
openssl x509 -noout -enddate
# Если дата в прошлом — сертификат истёк. Обнови.
# Для Let's Encrypt — проверить автообновление:
certbot renew --dry-run
# или:
systemctl status certbot.timer
Настройка TLS в Postfix
# /etc/postfix/main.cf — параметры TLS:
# Входящие соединения (smtpd = сервер):
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.yourdomain.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.yourdomain.com/privkey.pem
smtpd_tls_security_level = may
# may = предлагать TLS, не требовать.
# encrypt = требовать TLS. Осторожно — может сломать старых клиентов.
# Исходящие соединения (smtp = клиент):
smtp_tls_security_level = may
smtp_tls_loglevel = 1
# loglevel=1 — логировать TLS-соединения. Помогает при отладке.
# Кэш TLS-сессий:
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
# Применить:
postfix check && systemctl reload postfix
# Проверить в логах что TLS поднимается:
grep -i "tls" /var/log/mail.log | tail -20
# Ищем: "TLS connection established" — хорошо.
# "STARTTLS not available" — TLS не поднялся, смотри конфиг.
# "certificate verify failed" — проблема с сертификатом.
TLS в Exim
# Проверить что Exim поддерживает TLS:
exim -bV | grep -i tls
# Ищем: Support for: ... TLS
# Проверить TLS-соединение к своему Exim:
openssl s_client -starttls smtp -connect localhost:587
# Логи TLS в Exim (включить если нет):
# В /etc/exim4/exim4.conf добавь в секцию main:
# log_selector = +tls_peerdn +tls_certificate_verified
# Применить:
systemctl reload exim4
grep -i tls /var/log/exim4/mainlog | tail -20
Шаг 9 — SMTP relay: SendGrid, Mailgun, Amazon SES
Если порт 25 заблокирован провайдером и они не открывают — relay через внешний сервис. Это вообще правильнее для серьёзных рассылок: репутация IP у SendGrid уже наработана, доставляемость выше, blacklist не твоя проблема.
%%{init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#ffffff',
'primaryTextColor': '#1e293b',
'primaryBorderColor': '#94a3b8',
'lineColor': '#64748b',
'fontSize': '15px',
'fontFamily': 'ui-sans-serif, system-ui, sans-serif'
},
'flowchart': {'curve': 'linear', 'nodeSpacing': 50, 'rankSpacing': 50}
}}%%
flowchart LR
APP["Postfix\nна твоём VPS"]
RELAY["SMTP Relay\nSendGrid / Mailgun / SES\nПорт 587"]
DEST["Получатель\nGmail / Outlook"]
APP -->|"Аутентификация\nAPI key / SASL"| RELAY
RELAY -->|"Проверенный IP\nВысокая репутация"| DEST
style APP fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#1e40af
style RELAY fill:#f8fafc,stroke:#f97316,stroke-width:2px,color:#c2410c
style DEST fill:#f8fafc,stroke:#22c55e,stroke-width:2px,color:#15803d
Схема 2: SMTP relay — Postfix отправляет через внешний сервис. Твой IP не важен, важна репутация relay-провайдера.
# /etc/postfix/main.cf — relay через SendGrid:
relayhost = [smtp.sendgrid.net]: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
header_size_limit = 4096000
# Создать файл с паролями:
echo "[smtp.sendgrid.net]:587 apikey:ТУТ_ТВОЙ_API_KEY" > /etc/postfix/sasl_passwd
postmap /etc/postfix/sasl_passwd
chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
# Применить:
systemctl reload postfix
# Тест через swaks:
swaks --to test@gmail.com --from sender@yourdomain.com \
--server smtp.sendgrid.net --port 587 \
--auth-user apikey --auth-password "ТУТ_ТВОЙ_API_KEY" --tls
Для Mailgun — замени хост на smtp.mailgun.org и используй SMTP credentials из панели. Для Amazon SES — email-smtp.us-east-1.amazonaws.com:587, credentials из IAM. Логика та же.
Коды ошибок SMTP: расшифровка
В логах есть числа. Они не случайные. Вот что значат.
| Код |
Что означает |
Первый шаг |
| 220 |
Сервер готов |
Норма, соединение установлено |
| 250 |
Команда принята |
Норма |
| 421 |
Сервис временно недоступен |
Принимающий сервер перегружен — deferred, попробует позже |
| 450 |
Ящик временно недоступен |
Временная ошибка, будет retry |
| 451 |
Ошибка обработки на сервере |
Проверь /etc/resolv.conf, DNS-резолвер |
| 452 |
Недостаточно места |
df -h — проверь диск на сервере |
| 500 |
Синтаксическая ошибка команды |
Неверная команда в SMTP-сессии |
| 501 |
Неверные параметры команды |
Проверь формат MAIL FROM / RCPT TO |
| 550 |
Ящик не найден / отказ доставки |
Адрес не существует или заблокирован |
| 550 5.7.1 |
SPF check failed |
Добавь ip4:IP в SPF-запись домена |
| 550 5.7.26 |
DMARC policy violation |
Проверь SPF+DKIM, оба должны пройти |
| 553 |
Неверный адрес отправителя |
Проверь myhostname и myorigin в main.cf |
| 554 |
Transaction failed |
IP в blacklist или письмо содержит спам-контент |
| 535 |
Authentication failed |
Неверный логин/пароль — проверь sasl_passwd |
| 534 |
Authentication mechanism too weak |
Включи STARTTLS — сервер не принимает пароли без шифрования |
Типовые сообщения из логов
| Ошибка в логах |
Причина |
Решение |
| relay access denied |
Postfix не пускает как relay без авторизации |
Настрой SASL auth, проверь mynetworks |
| Connection refused (port 25) |
MTA не слушает или провайдер режет |
systemctl status postfix, тикет провайдеру |
| Connection timed out |
Файрвол режет исходящие соединения |
Проверь iptables/ufw, попробуй relay |
| SASL authentication failed |
Неверный логин/пароль для relay |
Проверь sasl_passwd, пересоздай postmap |
| mail for X loops back to myself |
Неверный mydestination или myhostname |
Убери домен из mydestination |
| STARTTLS not available |
TLS не настроен или сертификат недействителен |
Проверь cert_file/key_file в main.cf |
| certificate verify failed |
Сертификат истёк или самоподписанный |
certbot renew, проверь дату сертификата |
| deferred (host or domain not found) |
DNS не резолвит MX получателя |
Проверь /etc/resolv.conf, смени DNS на 8.8.8.8 |
| fatal: open /etc/postfix/main.cf: Permission denied |
Права на конфиг сломаны |
chown root:root /etc/postfix/main.cf, chmod 644 |
| warning: SASL: Connect to private/auth failed |
Dovecot не запущен или сокет не там |
systemctl status dovecot, проверь smtpd_sasl_path |
Скрипт автодиагностики SMTP
Хватит делать всё по одному. Скрипт пробегается по всем ключевым точкам и выдаёт отчёт за 30 секунд. Скопируй, сохрани, запусти.
#!/bin/bash
# ================================================
# smtp_diag.sh — Диагностика SMTP-сервера Linux
# Использование: sudo bash smtp_diag.sh yourdomain.com 1.2.3.4
# ================================================
DOMAIN="${1:-yourdomain.com}"
SERVER_IP="${2:-$(curl -s https://api.ipify.org 2>/dev/null)}"
REVERSED_IP=$(echo "$SERVER_IP" | awk -F. '{print $4"."$3"."$2"."$1}')
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
ok() { echo -e "${GREEN}OK ${NC} $1"; }
fail() { echo -e "${RED}FAIL ${NC} $1"; }
warn() { echo -e "${YELLOW}WARN ${NC} $1"; }
echo "========================================"
echo " SMTP Диагностика | IT-Apteka.com"
echo " Домен: $DOMAIN | IP: $SERVER_IP"
echo "========================================"
# 1. MTA
echo; echo "[ 1/8 ] Почтовый агент (MTA)"
MTA_FOUND=0
for MTA in postfix exim4 exim sendmail; do
if systemctl is-active --quiet "$MTA" 2>/dev/null; then
ok "$MTA запущен"
MTA_FOUND=1; break
fi
done
[ $MTA_FOUND -eq 0 ] && fail "Ни один MTA не запущен (postfix/exim/sendmail)"
# 2. Порты
echo; echo "[ 2/8 ] Порты SMTP (локально)"
for PORT in 25 587 465; do
if ss -tlnp | grep -q ":$PORT "; then
ok "Порт $PORT слушает"
else
warn "Порт $PORT не слушает"
fi
done
# 3. Исходящий порт 25
echo; echo "[ 3/8 ] Исходящий порт 25 (к Google MX)"
if timeout 8 bash -c 'echo QUIT | telnet aspmx.l.google.com 25 2>&1' | grep -q "220"; then
ok "Исходящий порт 25 открыт"
else
fail "Исходящий порт 25 заблокирован — провайдер или файрвол"
fi
# 4. PTR
echo; echo "[ 4/8 ] PTR-запись (обратный DNS)"
PTR=$(dig -x "$SERVER_IP" +short 2>/dev/null | head -1)
if [ -n "$PTR" ]; then
ok "PTR настроен: $PTR"
else
fail "PTR-запись отсутствует для IP $SERVER_IP"
fi
# 5. SPF
echo; echo "[ 5/8 ] SPF-запись"
SPF=$(dig TXT "$DOMAIN" +short 2>/dev/null | grep -i "v=spf1")
if [ -n "$SPF" ]; then
ok "SPF найден: $SPF"
echo "$SPF" | grep -q "$SERVER_IP" && \
ok "IP сервера включён в SPF" || \
warn "IP $SERVER_IP может не быть в SPF — проверь вручную"
else
fail "SPF-запись отсутствует для $DOMAIN"
fi
# 6. DKIM
echo; echo "[ 6/8 ] DKIM (селектор 'mail')"
DKIM=$(dig TXT "mail._domainkey.$DOMAIN" +short 2>/dev/null)
if [ -n "$DKIM" ]; then
ok "DKIM-запись найдена"
else
fail "DKIM не найден (mail._domainkey.$DOMAIN)"
fi
# 7. DMARC
echo; echo "[ 7/8 ] DMARC"
DMARC=$(dig TXT "_dmarc.$DOMAIN" +short 2>/dev/null | grep -i "v=DMARC1")
if [ -n "$DMARC" ]; then
ok "DMARC найден: $DMARC"
else
warn "DMARC-запись отсутствует (не критично, но желательно)"
fi
# 8. Blacklist
echo; echo "[ 8/8 ] Blacklist"
LISTS=("zen.spamhaus.org" "bl.spamcop.net" "dnsbl.sorbs.net" "b.barracudacentral.org")
for LIST in "${LISTS[@]}"; do
RESULT=$(dig +short "${REVERSED_IP}.${LIST}" 2>/dev/null)
[ -n "$RESULT" ] && fail "IP найден в $LIST ($RESULT)" || ok "Чист: $LIST"
done
echo; echo "========================================"
echo " Готово. Домен: $DOMAIN | IP: $SERVER_IP"
echo " $(date)"
echo "========================================"
# Сохранить и запустить:
chmod +x smtp_diag.sh
sudo bash smtp_diag.sh yourdomain.com 1.2.3.4
Осложнения: чек-лист последней надежды
Прошёл все шаги, всё зелёное, а письма всё равно не уходят. Одна капля никотина убивает лошадь. Одна строчка в main.cf без перезагрузки — всю диагностику.
Проверить hostname. Должен совпадать с PTR-записью, быть FQDN.
hostname -f
# Должно быть: mail.yourdomain.com
# Не так — исправь в /etc/hostname и /etc/hosts, потом hostname -F /etc/hostname
Проверить диск. Postfix молча падает при 100% заполнении.
df -h
# /var или / под завязку — чисти
du -sh /var/spool/postfix/deferred/
du -sh /var/log/
# Ротировать логи:
logrotate -f /etc/logrotate.d/rsyslog
SELinux / AppArmor на пути.
# SELinux:
getenforce
# Enforcing — попробуй временно:
setenforce 0
# Смотреть что блокирует:
grep postfix /var/log/audit/audit.log | grep denied | tail -20
# AppArmor:
aa-status | grep postfix
Права на директории Postfix.
postfix set-permissions
ls -la /var/spool/postfix/
Конфиг прошёл check, но не перезагружен.
postfix check && systemctl reload postfix
# reload — применяет main.cf без разрыва соединений
# restart — полный перезапуск, если reload не помог
Gmail отбивает конкретно твой домен. Зарегистрируй домен в Google Postmaster Tools — там видна репутация и причины блокировок: postmaster.google.com
Outlook / Microsoft блокирует. Подай заявку через Sender Support: sendersupport.olc.protection.outlook.com
Профилактика: как не получить это в следующий раз
Скрипт мониторинга очереди — добавь в cron, он пришлёт алерт если что-то пошло не так:
#!/bin/bash
# /usr/local/bin/check_mailq.sh
# Crontab: */15 * * * * /usr/local/bin/check_mailq.sh
THRESHOLD=100
ADMIN_EMAIL="admin@yourdomain.com"
QUEUE_SIZE=$(postqueue -p 2>/dev/null | tail -1 | grep -oP '^\d+')
if [ -n "$QUEUE_SIZE" ] && [ "$QUEUE_SIZE" -gt "$THRESHOLD" ]; then
echo "ALERT: В очереди Postfix $QUEUE_SIZE писем на $(hostname) в $(date)" \
| mail -s "Postfix queue alert" "$ADMIN_EMAIL"
fi
chmod +x /usr/local/bin/check_mailq.sh
(crontab -l 2>/dev/null; echo "*/15 * * * * /usr/local/bin/check_mailq.sh") | crontab -
Три правила которые избавят от большинства проблем: мониторинг очереди раз в 15 минут, проверка blacklist раз в неделю через MXToolbox, и никогда не запускать массовые рассылки прямо с боевого сервера. Для рассылок — отдельный IP или внешний сервис. Репутация IP нарабатывается месяцами, сжигается за час.
FAQ: вопросы про диагностику SMTP на Linux
Почему письма уходят в спам а не во входящие?
Почти всегда одна из трёх причин: IP в blacklist, SPF не включает IP сервера, или DKIM не настроен. Проверяй в таком порядке: скрипт blacklist-проверки → dig TXT домен +short | grep spf → dig TXT mail._domainkey.домен +short. Если всё три ок — проверь mail-tester.com, он покажет скоринг и конкретные причины.
Как понять что именно Postfix пишет в deferred и почему не отправляет?
# Посмотреть причину deferred для каждого письма:
postqueue -p | grep "^[A-F0-9]" | while read id rest; do
echo "=== $id ==="
postcat -q "$id" 2>/dev/null | grep -E "reason|error|host|status"
done
# Или прямо из логов — причина всегда рядом с "deferred":
grep "deferred" /var/log/mail.log | tail -20
Что делать если провайдер не открывает порт 25?
Переходи на SMTP relay через порт 587. SendGrid даёт 100 писем в день бесплатно, Mailgun — 1000 в месяц, Amazon SES — 62000 в месяц если сервер на EC2. Настройка занимает 20 минут по инструкции выше. Это вообще правильнее для боевого сервера: не надо следить за репутацией IP, доставляемость выше.
Как проверить что DKIM-подпись валидна?
# Отправить письмо на check-auth@verifier.port25.com:
echo "Test" | mail -s "DKIM test" check-auth@verifier.port25.com
# Через минуту придёт автоответ с результатами проверки SPF/DKIM/DMARC
# Или через swaks и потом проверить заголовки полученного письма:
swaks --to check-auth@verifier.port25.com --from test@yourdomain.com --server localhost
Exim или Postfix — что выбрать для нового сервера?
На новом сервере — Postfix. Проще конфиг, лучше документация, большинство туториалов под него. Exim стоит по умолчанию на Debian и на хостингах с cPanel — там не выбираешь. Если уже стоит Exim и работает — не трогай без причины.
Итог
Диагностика SMTP-сервера на Linux — это последовательность из восьми проверок, не гадание на кофейной гуще. MTA запущен, порт открыт, DNS настроен, IP чист, TLS работает. Каждый пункт — одна команда, результат — сразу.
Если после всего этого письма всё равно не уходят — переходи на SMTP relay. Это не поражение, это правильное решение для большинства VPS где провайдер режет 25-й порт и не собирается его открывать.
Не помогло — пишите в комментарии
Если прошли весь чек-лист и получили нестандартный код ошибки — пишите. Разберём. Подписывайтесь на телеграм IT-Apteka
— туда выходят новые рецепты без воды.