Заметки
Тему письма в mail() нужно кодировать отдельно
Почему русская тема письма через PHP mail() может отображаться некорректно и как закодировать её в UTF-8.
Для тела письма можно указать charset=UTF-8, но для темы этого недостаточно.
Тема находится в заголовке Subject, поэтому её нужно кодировать отдельно.
Проблема
При отправке письма через mail() русская тема может прийти в почтовый клиент
кракозябрами, даже если тело письма отображается нормально.
Тело письма и тема письма кодируются по-разному. Для тела обычно достаточно указать кодировку в заголовке:
Content-Type: text/plain; charset=UTF-8
Но тема письма — это заголовок Subject. Для русского текста в заголовке
нужен формат MIME encoded-word:
=?UTF-8?B?BASE64_TEXT?=
Если передать русскую тему в mail() как обычную строку, часть почтовых клиентов
может отобразить её неправильно.
Решение
Перед отправкой тему нужно преобразовать в MIME encoded-word. Для простого случая подойдёт вариант с UTF-8 и Base64.
Минимальный вариант:
<?php
$subject = 'Заявка обновлена';
$encoded_subject = '=?UTF-8?B?' . base64_encode($subject) . '?='; Лучше вынести кодирование в отдельную функцию, чтобы не собирать заголовок вручную в каждом месте отправки.
<?php
/**
* Кодирует тему письма для заголовка Subject.
*/
function encodeMailSubject(string $subject): string
{
return '=?UTF-8?B?' . base64_encode($subject) . '?=';
} Пример отправки
Пример ниже показывает базовую отправку текстового письма через mail().
Для очередей, повторных попыток и массовых уведомлений лучше использовать отдельный
почтовый механизм.
<?php
const MAIL_TO = 'user@example.com';
const MAIL_FROM = 'noreply@example.com';
$subject = 'Заявка обновлена';
$message = 'В CRM изменилась заявка.';
sendPlainTextMail(MAIL_TO, MAIL_FROM, $subject, $message);
/**
* Отправляет простое текстовое письмо.
*/
function sendPlainTextMail(string $recipient_email, string $sender_email, string $subject, string $message): bool
{
$encoded_subject = encodeMailSubject($subject);
$headers = buildMailHeaders($sender_email);
return mail($recipient_email, $encoded_subject, $message, $headers);
}
/**
* Кодирует тему письма для заголовка Subject.
*/
function encodeMailSubject(string $subject): string
{
return '=?UTF-8?B?' . base64_encode($subject) . '?=';
}
/**
* Собирает заголовки письма.
*/
function buildMailHeaders(string $sender_email): string
{
$headers = [
'MIME-Version: 1.0',
'Content-Type: text/plain; charset=UTF-8',
'From: ' . $sender_email,
];
return implode("\r\n", $headers);
}
В этом примере тема кодируется отдельно, а тело остаётся обычным UTF-8 текстом.
Кодировка тела задаётся через Content-Type.