Функция PHP mail() может вернуть успешный результат, но это не означает, что письмо доставлено. Она только передает письмо локальному почтовому агенту.

Дальше письмо может застрять в очереди, быть отклонено Mail.ru или Gmail, попасть в спам или уйти с неправильными заголовками.

Кому нужна такая доработка

Разбор нужен, если старый PHP-сайт, форма или самописная CMS отправляет письма через mail(), но уведомления не доходят.

  • mail() возвращает true, но письма нет
  • письма застряли в очереди Exim
  • почтовик пишет spam rejected
  • после переноса сайта почта сломалась
  • письма приходят с непонятным отправителем

Почему задача часто работает нестабильно

Локальная отправка не настроена

На сервере может быть sendmail, Exim или Postfix, но он не обязан быть настроен для нормальной внешней доставки.

Неверные заголовки

Ошибки в From, Reply-To, Content-Type и кодировке часто приводят к отклонению письма.

Нет DNS-авторизации

SPF, DKIM и DMARC помогают доказать, что письмо действительно отправлено вашим доменом.

Нужен SMTP

Для коммерческих форм часто лучше отправлять через SMTP доменной почты или почтового сервиса.

Что проверить перед началом

Чем точнее исходные данные, тем быстрее можно оценить задачу и не трогать лишние части сайта. Обычно достаточно ссылки, описания ошибки и доступов к той части, где выполняется настройка.

  • проверьте sendmail_path в PHP
  • посмотрите очередь mailq
  • проверьте mail-логи Exim/Postfix
  • проверьте From и Reply-To
  • проверьте SPF/DKIM домена

Как я это делаю

Я проверяю PHP-код отправки, локальный MTA, заголовки, очередь, bounce-сообщения и DNS. Если mail() ненадежен, перевожу отправку на SMTP.

  1. Проверяю текущую схему: сайт, сервер, форму, сервис, API или cron.
  2. Фиксирую проблему или нужный сценарий на тестовом примере.
  3. Делаю точечную настройку, скрипт или интеграцию.
  4. Проверяю результат как пользователь и оставляю понятное описание выполненной работы.

Что лучше не делать

  • не считать true от mail() гарантией доставки
  • не отправлять от имени чужого домена
  • не игнорировать очередь Exim
  • не добавлять случайные заголовки без CRLF

Сроки

Проверка mail() и заголовков30-90 минут
Настройка SMTP вместо mail()1-2 часа
Серверная почта и DNSиндивидуально

Связанные материалы

Вопрос-ответ

Почему mail() возвращает true?

Потому что письмо принято локальной системой отправки, но доставка до получателя еще не произошла.

Что лучше вместо mail()?

SMTP с авторизацией, корректным From и нормальными DNS-записями домена.

Можно ли посмотреть причину отказа?

Да, часто она есть в mail-логах или bounce-сообщении от удаленного сервера.

Итог

PHP mail() нужно проверять не по return true, а по реальной доставке, логам, заголовкам и ответам почтовых сервисов.

Если нужна такая настройка или ремонт, напишите в Telegram: @rabotator_support. Коротко посмотрю задачу, скажу реальный объем и предложу аккуратный вариант решения.