Почта WordPress не уходит: настройка SMTP и wp_mail для писем

Почта WordPress не уходит: настройка SMTP и wp_mail для писем

Кратко: письма WordPress не доходят, потому что по умолчанию функция wp_mail() отправляет их через PHP-функцию mail() без логина и пароля — сервер-получатель считает такие письма подозрительными и прячет их в спам или отбрасывает вовсе. Лечение в три шага: SMTP-плагин (WP Mail SMTP или FluentSMTP), ящик на домене сайта и DNS-записи SPF/DKIM. Ниже — тест-сниппет для проверки почты за минуту, три способа настройки SMTP с готовым кодом, раздел про SPF/DKIM и таблица частых ошибок.

Почему письма WordPress не доходят: как работает wp_mail() по умолчанию

В ядре WordPress есть собственный почтовый механизм. Функция wp_mail() — обёртка над библиотекой PHPMailer, которая по умолчанию вызывает PHP-функцию mail() вашего хостинга. Схема выглядит просто: форма отправила данные → WordPress собрал письмо → PHP передал его локальному почтовому серверу → тот попытался доставить письмо на сервер получателя. Проблема в том, что на каждом шаге письмо остаётся «анонимным».

Вот почему письма, отправленные через mail(), почти всегда попадают в спам:

  • Нет аутентификации. Письмо уходит без логина и пароля — как открытка без отправителя. Почтовые сервисы (Gmail, Яндекс, Mail.ru) доверяют письмам, отправленным с логином и паролем через SMTP, а «безликие» — нет.
  • Неверный отправитель. Часто письмо подписано wordpress@vashdomen.ru или вовсе nobody@имя-сервера-хостинга — домен отправителя не совпадает с доменом сайта, и спам-фильтр срабатывает мгновенно.
  • Отсутствуют SPF и DKIM. Получающий сервер проверяет DNS-записи домена: разрешено ли этому серверу вообще отправлять за него письма. Без записей доверия нет — есть запись в спаме.
  • Хостинг может блокировать отправку. На многих shared-тарифах функция mail() отключена или ограничена: письмо «успешно отправилось», но на деле его выбросил локальный фильтр.

Важно понимать: форма на сайте при этом честно говорит «Сообщение отправлено» — она вызвала wp_mail(), та вернула true. Правда ли письмо дошло, WordPress не знает. Поэтому диагностику начинаем не с формы, а с самой почты. Если вы пока не знакомы с тем, как в WordPress подключаются свои функции, сначала пробегитесь по материалу о том, как работают хуки WordPress: actions и filters, — без этого понимания половина кода ниже покажется магией.

И ещё одна частая ловушка новичков: письма теряются не из-за WordPress, а из-за окружения. Локальная сборка (OpenServer, XAMPP) вообще не умеет отправлять почту — там wp_mail() всегда молчит. А на хостинге письмо может уходить с задержкой через планировщик wp-cron, если плагин форм поставил отправку в очередь. Об этом — в разделе про логирование.

Быстрая диагностика: отправляет ли wp_mail() письма вообще

Прежде чем что-то настраивать, проверьте базовую отправку. Добавьте тестовый сниппет в functions.php дочерней темы:

add_shortcode( 'ds_mail_test', function () {
    $to  = get_option( 'admin_email' ); // почта админа из настроек сайта
    $ok  = wp_mail(
        $to,
        'Тест почты с сайта ' . get_bloginfo( 'name' ),
        'Если видите это письмо — wp_mail() на сайте работает.'
    );

    return $ok
        ? 'Письмо отправлено на ' . $to . '. Проверьте «Входящие» и папку «Спам».'
        : 'Отправка не удалась. Включите лог ошибок (раздел 10) и повторите.';
} );

Сниппет регистрирует шорткод [ds_mail_test]. Вставьте его на любую черновую страницу, откройте её — код отправит письмо на адрес администратора, указанный в «Настройки → Общие». Если вы собираете много таких разовых сниппетов, удобнее держать их в одном месте — у нас есть подборка полезных сниппетов для functions.php с похожими приёмами.

Дальше три сценария:

  1. Письмо во «Входящих» — базовая отправка работает, но это не гарантия: письмо к самому себе хостинг почти всегда доставит. Проблема всплывает на внешних получателях.
  2. Письмо в «Спаме» — классика: отправка идёт через mail() без SMTP. Читаем разделы 3–6.
  3. Письма нет нигде — либо mail() отключена хостером, либо ошибка отправки. Переходите к разделу про логирование и обязательно заведите SMTP.

Для объективной оценки отправки используйте сервис mail-tester.com: он выдаёт уникальный адрес, на который нужно отправить письмо, и показывает оценку от 0 до 10 с расшифровкой — чего именно не хватает домену (SPF, DKIM, корректный заголовок). Цель — 10 из 10 после настройки SMTP.

Способ 1. Плагин WP Mail SMTP: настройка по шагам

Самый быстрый и безопасный путь для новичка — плагин WP Mail SMTP. Он перехватывает все вызовы wp_mail() и переправляет письма через SMTP-сервер с аутентификацией: письма идут так же, как если бы вы отправляли их из почтового клиента.

Пошаговый порядок:

  1. Создайте ящик на домене сайта — например, no-reply@vashdomen.ru. Это делается в панели хостинга в разделе «Почта» (если почта не на хостинге, а у провайдера вроде Яндекс 360 — берите данные оттуда). Ящик именно на домене сайта, а не на gmail.com: письма от «чужого» домена от своего имени — прямая дорога в спам.
  2. Установите плагин «WP Mail SMTP» из каталога плагинов. Про выбор и установку плагинов у нас есть отдельный гайд — топ-10 плагинов WordPress для начинающих.
  3. Заполните настройки. Мастер предложит провайдеров (Gmail, SendGrid, Brevo и другие) — если у вас обычная хостинг-почта, выбирайте Other SMTP. Данные берутся из панели хостинга:
    • SMTP Host — например smtp.vashdomen.ru или mail.timeweb.ru (уточните у хостера);
    • Encryption — SSL для порта 465 или TLS для порта 587;
    • SMTP Username — полный ящик no-reply@vashdomen.ru;
    • SMTP Password — пароль ящика (или «пароль приложения», если у провайдера включена двухфакторка);
    • From Email / From Name — тот же ящик и название сайта, включите «Force From Email».
  4. Отправьте тестовое письмо встроенной кнопкой «Email Test» и проверьте почтовый тестер из раздела 2.

Типичные грабли: порт 25 закрыт у хостера (используйте 465/587), пароль с пробелами скопирован вместе с лишним символом, а в поле From указан ящик с другого домена. Все эти случаи разбираем в таблице ошибок в разделе 11.

Альтернативные SMTP-плагины: что выбрать

WP Mail SMTP — не единственный вариант. Полезно знать альтернативы: некоторые дают лог писем бесплатно, другие проще в настройке. Сравнение:

Плагин Сложность Лог писем Особенности
WP Mail SMTP Просто, мастер настройки В Pro-версии Де-факто стандарт, много инструкций, есть тест-письмо
FluentSMTP Просто Бесплатно, прямо в админке Бесплатный лог и повторная отправка — удобно для форм
Post SMTP Средняя Бесплатно Подробная диагностика соединения и конфигуратор
Easy WP SMTP Просто В новых версиях есть Минимализм, только SMTP без внешних сервисов

Практическая рекомендация: если нужен только «чтобы письма доходили» — берите WP Mail SMTP; если важно видеть каждое письмо и иметь возможность переслать потерянное — FluentSMTP. SMTP решает и проблему писем от контактных форм WordPress: уведомления с форм пойдут тем же надёжным каналом.

Способ 2. SMTP без плагина: сниппет phpmailer_init

Если не хотите лишний плагин (например, на сайте и так их два десятка), SMTP настраивается кодом через хук phpmailer_init — он срабатывает перед отправкой каждого письма и позволяет добраться до объекта PHPMailer:

// SMTP для wp_mail() без плагина
add_action( 'phpmailer_init', function ( $phpmailer ) {
    $phpmailer->isSMTP();
    $phpmailer->Host       = 'smtp.vashdomen.ru';     // сервер исходящей почты
    $phpmailer->Port       = 465;                     // 465 = SSL, 587 = TLS
    $phpmailer->SMTPAuth   = true;                    // логин и пароль обязательны
    $phpmailer->SMTPSecure = 'ssl';                   // 'tls' для порта 587
    $phpmailer->Username   = 'no-reply@vashdomen.ru';
    $phpmailer->Password   = defined( 'DS_SMTP_PASS' ) ? DS_SMTP_PASS : '';
} );

// отправитель по умолчанию для всех писем сайта
add_filter( 'wp_mail_from', function () {
    return 'no-reply@vashdomen.ru';
} );

add_filter( 'wp_mail_from_name', function () {
    return get_bloginfo( 'name' );
} );

Обратите внимание на пароль: он подставляется из константы DS_SMTP_PASS. Определите её в wp-config.php, до строки «That’s all, stop editing!»:

define( 'DS_SMTP_PASS', 'parol-ot-yashchika' );

Почему не хранить пароль прямо в functions.php? Во-первых, это файл темы: пароль попадёт в резервные копии, репозиторий и любые экспорты кода. Во-вторых, редактор файлов в админке показывает содержимое всем, кто имеет доступ. Ключи в wp-config.php — минимальная гигиена из правил безопасности WordPress для новичков.

Код кладётся в functions.php дочерней темы или в mu-плагин в папке wp-content/mu-plugins. После вставки запустите тест из раздела 2 — письмо должно уйти уже через SMTP. Если PHPMailer выбрасывает ошибку соединения — сверьте пару «порт + шифрование»: комбинация «465 + tls» или «587 + ssl» — самая частая ошибка новичков.

SPF, DKIM и DMARC: чтобы письма не падали в спам

SMTP-плагин решает половину задачи: теперь письма аутентифицируются на отправке. Вторая половина — доказать миру, что ваш сервер имеет право отправлять письма от домена сайта. Это делают три DNS-записи, которые добавляются в панели управления доменом (там же, где вы настраивали домен для сайта):

  • SPF — текстовая запись, перечисляющая серверы, которым разрешено отправлять почту от имени домена. Пример для сайта на хостинге Timeweb:
    v=spf1 a mx include:_spf.timeweb.ru ~all

    Точный include у каждого хостера свой — он указан в инструкции к почте.

  • DKIM — цифровая подпись: сервер подписывает письмо ключом, а получатель сверяет подпись с публичным ключом в DNS. Ключ генерируется в панели хостинга при создании ящика — вам остаётся добавить TXT-запись вида selector._domainkey.vashdomen.ru.
  • DMARC — политика: что делать получателю, если SPF/DKIM не сошлись. Для старта достаточно мягкой политики:
    v=DMARC1; p=none; rua=mailto:admin@vashdomen.ru

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

После добавления записей подождите пару часов (DNS обновляется не мгновенно) и прогоните письмо через mail-tester.com. Если SPF или DKIM в отчёте красные — перепроверьте запись: лишний пробел или отсутствующая точка ломают синтаксис. Правильно настроенный конверт (SPF + DKIM + DMARC + согласованный From) — это 9 из 10 баллов тестера без единой строчки кода.

От кого идут письма: wp_mail_from и wp_mail_from_name

Даже с настроенным SMTP WordPress по умолчанию подставляет в поле «От» технический адрес wordpress@vashdomen.ru и имя «WordPress». Получатель видит подозрительное письмо от несуществующего ящика — доверия ноль, да и ответы на такое письмо уходят в никуда. Два фильтра это исправляют:

add_filter( 'wp_mail_from', function ( $from_email ) {
    // единый адрес отправителя для всего сайта
    return 'no-reply@vashdomen.ru';
} );

add_filter( 'wp_mail_from_name', function ( $from_name ) {
    return 'Интернет-магазин Пчёлка'; // или get_bloginfo( 'name' )
} );

Три правила, которые нельзя нарушать:

  1. Домен адреса From должен совпадать с доменом сайта. Письмо «от поддержки@сайт.ру», отправленное через SMTP чужого домена, — гарантированный спам.
  2. Адрес From должен быть согласован с SPF — то есть домен из From входит в SPF-запись.
  3. Для ответов используйте Reply-To, а не From: ящик no-reply@ не читает входящие, а реальные вопросы клиентов должен получать живой человек:
    $headers = [ 'Reply-To: Отдел продаж <sales@vashdomen.ru>' ];
    wp_mail( $to, $subject, $body, $headers );

HTML-письма, вложения и массовая отправка

wp_mail() умеет больше, чем «текст + тема». По умолчанию письма уходят в text/plain, но красивое письмо-уведомление с кнопками делается одним заголовком:

// HTML-письмо о новом заказе
$headers = [
    'Content-Type: text/html; charset=UTF-8',
    'Reply-To: sales@vashdomen.ru',
];

$body = '<h2 style="margin:0 0 12px">Заказ №128 принят</h2>'
      . '<p>Клиент: ' . esc_html( $name ) . '</p>'
      . '<p>Сумма: ' . esc_html( $total ) . ' ₽</p>'
      . '<p><a href="https://vashdomen.ru/orders/128">Открыть заказ</a></p>';

wp_mail( 'manager@vashdomen.ru', 'Новый заказ №128', $body, $headers );

Пятый аргумент функции — вложения. Передавайте абсолютные пути к файлам на сервере, а не URL:

$upload = wp_get_upload_dir();

wp_mail(
    'client@example.com',
    'Счёт на оплату заказа №128',
    'Здравствуйте! Счёт во вложении. Оплатить можно до 20.09.',
    [],
    [ $upload['basedir'] . '/invoices/invoice-128.pdf' ] // путь на сервере
);

Массовая отправка — отдельная дисциплина. Если в цикле на 300 адресов вызвать wp_mail() подряд, скрипт упрётся в лимит времени PHP и часть писем уйдёт «в никуда». Правильный приём — поставить отправку в очередь через планировщик: каждое письмо отправляется отдельным запуском wp-cron, сайт не тормозит, а упавшая отправка повторяется. Для регулярных рассылок (новости, дайджесты) SMTP хостинга всё равно не годится — лимиты хостеров рассчитаны на уведомления, а не на рассылки; там используют сервисы вроде Unisender или Brevo, у которых wp_mail() настраивается тем же плагином из раздела 3.

Письмо с формы сайта: REST-endpoint и JavaScript

Соберём всё вместе: свой endpoint REST API, который принимает заявку с формы и отправляет её письмом через wp_mail(). Такую связку удобно делать, когда стандартные плагины форм избыточны. Про REST у нас есть подробный гайд — REST API WordPress простыми словами; здесь — рабочий минимум.

PHP: регистрируем маршрут /wp-json/ds/v1/contact:

add_action( 'rest_api_init', function () {
    register_rest_route( 'ds/v1', '/contact', [
        'methods'             => 'POST',
        'permission_callback' => '__return_true',
        'callback'            => 'ds_contact_send',
        'args'                => [
            'name'    => [ 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ],
            'email'   => [ 'required' => true, 'sanitize_callback' => 'sanitize_email' ],
            'message' => [ 'required' => true, 'sanitize_callback' => 'sanitize_textarea_field' ],
        ],
    ] );
} );

function ds_contact_send( WP_REST_Request $request ) {
    // простая ловушка для ботов: скрытое поле должно остаться пустым
    if ( $request['website'] ) {
        return [ 'ok' => true ]; // боту говорим «спасибо» и молча игнорируем
    }

    $subject = 'Заявка с сайта: ' . $request['name'];
    $body    = "Имя: {$request['name']}\n"
             . "E-mail: {$request['email']}\n\n"
             . $request['message'];

    $sent = wp_mail( get_option( 'admin_email' ), $subject, $body, [
        'Reply-To: ' . $request['email'],
    ] );

    if ( ! $sent ) {
        return new WP_Error(
            'mail_failed',
            'Не удалось отправить заявку, позвоните нам.',
            [ 'status' => 500 ]
        );
    }

    return [ 'ok' => true ];
}

JavaScript на фронте отправляет заявку без перезагрузки страницы:

var form = document.getElementById( 'ds-contact' );

form.addEventListener( 'submit', function ( e ) {
    e.preventDefault();

    var payload = {
        name:    form.elements.name.value,
        email:   form.elements.email.value,
        message: form.elements.message.value,
        website: form.elements.website.value, // honeypot
    };

    fetch( DS_SITE.rest + 'ds/v1/contact', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json; charset=UTF-8' },
        body: JSON.stringify( payload ),
    } )
        .then( function ( r ) { return r.json(); } )
        .then( function ( res ) {
            form.reset();
            alert( res.ok
                ? 'Заявка отправлена! Ответим в течение часа.'
                : 'Не получилось. Позвоните нам, пожалуйста.' );
        } );
} );

Адрес REST и строку DS_SITE.rest передайте в скрипт через wp_localize_script():

wp_enqueue_script( 'ds-contact', get_stylesheet_directory_uri() . '/js/contact.js', [], '1.0', true );
wp_localize_script( 'ds-contact', 'DS_SITE', [
    'rest' => esc_url_raw( rest_url() ),
] );

Здесь применены три предохранителя: аргументы маршрута чистятся через sanitize_callback (никаких сырых $_POST), скрытое поле-«honeypot» отсекает простых ботов, а Reply-To подставляет адрес клиента — можно отвечать прямо из почтового клиента. Для публичной формы добавьте капчу и ограничение частоты запросов — приёмы разобраны в статье про контактные формы WordPress.

Логирование ошибок: куда смотрят, когда письма «пропадают»

Самое неприятное в почте — молчание. Чтобы wp_mail() не терялась без следа, подпишитесь на событие wp_mail_failed — оно срабатывает при каждой неудачной отправке и отдаёт объект WP_Error с текстом ошибки от SMTP-сервера:

add_action( 'wp_mail_failed', function ( WP_Error $error ) {
    error_log(
        current_time( 'mysql' ) . ' mail failed: '
        . $error->get_error_code() . ' — '
        . $error->get_error_message()
    );
} );

Чтобы записи попали в файл debug.log, включите в wp-config.php:

define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );   // лог в wp-content/debug.log
define( 'WP_DEBUG_DISPLAY', false ); // ошибки не показывать посетителям

После этого история с «пропавшими письмами» превращается в задачу на пять минут: в логе будет видно либо smtp_connect_failed (проблема сети/порта), либо 535 authentication failed (неверный логин/пароль), либо mail() on behalf of... (отправка всё ещё идёт мимо SMTP — проверьте настройки плагина).

Для просмотра лога не лезьте по FTP каждый раз: плагин Query Monitor покажет почтовые события прямо в админке, а FluentSMTP хранит каждое письмо с его статусом и текстом ошибки. И помните про очередь: если плагин форм ставит письма в отложенную отправку, ошибки всплывут не сразу, а при выполнении задачи крона — в его логе или в wp_mail_failed в момент запуска.

Частые ошибки SMTP и их решения

Сводная таблица ошибок, которые встречаются при настройке почты WordPress чаще всего:

Симптом Причина Решение
535 / Could not authenticate Неверный логин или пароль, у провайдера включена 2FA Проверьте логин (полный ящик) и создайте «пароль приложения»
Connection timed out (110) Исходящий порт 25/465/587 закрыт на хостинге Напишите в поддержку хостера открыть порт или смените порт
SSL/TLS handshake failed Не совпадает шифрование и порт 465 = SSL, 587 = STARTTLS (TLS); сверьте в настройках
Письма приходят в спам Нет SPF/DKIM или From с чужого домена Добавьте DNS-записи (раздел 6), единый From на домене сайта
Письма приходят с опозданием Отправка в очереди через wp-cron, крон лагает Переведите крон на серверный запуск по расписанию
From: wordpress@домен Не заданы фильтры отправителя wp_mail_from и wp_mail_from_name (раздел 7)
«Сообщение отправлено», писем нет Форма вызывает wp_mail(), но mail() отключена хостером Включите лог ошибок и настройте SMTP (разделы 3–5)

Если разбираться с портами и DNS некогда — это штатная задача для поддержки: у нас есть разбор, что входит в поддержку сайта и сколько она стоит. Настройка почты там занимает один первый час.

TimeWeb

Частые вопросы о почте WordPress и SMTP

Можно ли использовать Gmail или Яндекс-почту как SMTP для сайта?

Технически да: у Google и Яндекса есть SMTP-серверы и «пароли приложений» для сторонних программ. Но адрес отправителя будет с их домена, а не с домена сайта — часть получателей и спам-фильтров отнесётся к таким письмам плохо. Лучше завести ящик на своём домене у хостера или почтового провайдера и отправлять через него.

Какой порт и шифрование выбрать: 465 или 587?

Оба варианта рабочие: 465 работает по SSL сразу после подключения, 587 сначала открывает соединение открытым текстом и переключается на TLS командой STARTTLS. Главное — не смешивать: 465 требует в настройках «ssl», 587 — «tls». Если хостер поддерживает оба, начните с 465.

Где взять данные SMTP-сервера для настройки?

В панели хостинга в разделе «Почта» или в инструкции почтового провайдера: имя SMTP-сервера (обычно smtp.вашдомен.ru или сервер хостера), порт, тип шифрования и учётные данные — полный адрес ящика и пароль. Если данных нет в панели, их выдаст поддержка хостинга одним сообщением.

Обязательно ли ставить плагин, или достаточно кода в functions.php?

Достаточно кода: хук phpmailer_init с настройками SMTP полностью заменяет плагин (пример в разделе 5). Плагин удобнее новичку: есть мастер настройки, кнопка тест-письма и в некоторых версиях лог отправлений. Код выбирают, когда плагинов на сайте и так много или нужна жёсткая централизация настроек.

Почему письма всё равно попадают в спам даже с настроенным SMTP?

SMTP лишь аутентифицирует отправку. Если у домена нет SPF/DKIM, адрес From не согласован с этими записями или контент письма выглядит спамерски (кричащие заголовки, ссылки на сомнительные домены), письмо всё равно уедет в спам. Прогоните письмо через mail-tester.com — сервис покажет конкретную причину и подсказку.

Сколько писем можно отправлять с сайта, и что делать при больших объёмах?

Хостинг-почта рассчитана на уведомления: типичные лимиты — от сотен до пары тысяч писем в сутки, точные цифры у хостера. Превышение приводит к блокировке ящика. Для рассылок используйте специализированные сервисы (Brevo, Unisender): они подключаются тем же плагином WP Mail SMTP и выдерживают объёмы в десятки тысяч писем.

Вывод

Почта WordPress чинится по понятной цепочке: проверили базовую отправку тест-сниппетом → включили SMTP (плагином WP Mail SMTP или кодом через phpmailer_init) → задали единый отправитель фильтрами wp_mail_from/wp_mail_from_name → добавили SPF, DKIM и DMARC в DNS → включили лог wp_mail_failed, чтобы следующая проблема находилась за минуты, а не за дни. После каждого шага — тестовое письмо и mail-tester.com: цель 10 из 10 реально достижима за один вечер.

Если поднимаете сайт с нуля или форма — лишь часть задачи, посмотрите услуги разработки и настройки сайтов и живые кейсы в нашем портфолио; разборы SMTP, хуков и плагинов регулярно выходят в блоге о разработке WordPress. Нужна помощь с почтой на вашем сайте — напишите через форму контактов, настроим отправку и DNS так, чтобы письма доходили до клиентов, а не до папки «Спам».

Clearfy

Поделиться:
Telegram ВКонтакте