Symfony/Mailer для PHP: полное руководство по отправке почты
1. Что это и зачем нужна
Symfony/Mailer — это мощный и гибкий компонент экосистемы Symfony, предназначенный для отправки электронных писем из PHP-приложений. В отличие от встроенной функции PHP mail(), которая требует ручной настройки заголовков и MIME-типов, Symfony/Mailer предоставляет объектно-ориентированный API для создания, форматирования и отправки сообщений через различные транспорты (SMTP, Sendmail, API сторонних сервисов).
Основная задача библиотеки — абстрагировать процесс отправки почты, позволяя разработчику сосредоточиться на содержимом письма, а не на низкоуровневых деталях протоколов. Symfony/Mailer поддерживает HTML-шаблоны, вложения, встраивание изображений, подпись DKIM, а также интеграцию с популярными почтовыми сервисами через Mailer DSN (Data Source Name).
Библиотека незаменима для проектов, где требуется надежная отправка транзакционных писем (подтверждение регистрации, сброс пароля, уведомления), маркетинговых рассылок или любых других email-уведомлений. Благодаря модульной архитектуре Symfony/Mailer легко тестируется (через MockTransport) и масштабируется.
2. Установка
Установка производится через Composer — стандартный менеджер пакетов для PHP. Выполните в терминале в корне вашего проекта:
composer require symfony/mailer
Если вы используете Symfony Flex (рекомендуется), то после установки будет автоматически создан файл конфигурации config/packages/mailer.yaml. Для работы с популярными почтовыми сервисами (SendGrid, Mailgun, Amazon SES и др.) установите соответствующий адаптер, например:
composer require symfony/sendgrid-mailer
composer require symfony/mailgun-mailer
composer require symfony/amazon-mailer
Также потребуется компонент symfony/http-client для работы с API-транспортами:
composer require symfony/http-client
3. Быстрый старт — минимальный рабочий пример
После установки библиотеки вы можете отправить первое письмо буквально в несколько строк. Создайте файл send_email.php:
<?php
// send_email.php
require_once 'vendor/autoload.php';
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport;
use Symfony\Component\Mime\Email;
// 1. Создаем транспорт (SMTP-сервер Gmail)
$transport = new EsmtpTransport('smtp.gmail.com', 587, true);
$transport->setUsername('your-email@gmail.com');
$transport->setPassword('your-app-password'); // Используйте пароль приложения
// 2. Создаем Mailer
$mailer = new Mailer($transport);
// 3. Создаем письмо
$email = (new Email())
->from('your-email@gmail.com')
->to('recipient@example.com')
->subject('Привет от Symfony Mailer!')
->text('Это тестовое письмо, отправленное с помощью Symfony/Mailer.')
->html('<h1>Привет!</h1><p>Это <strong>HTML</strong> версия письма.</p>');
// 4. Отправляем
try {
$mailer->send($email);
echo "Письмо отправлено успешно!\n";
} catch (\Exception $e) {
echo "Ошибка: " . $e->getMessage() . "\n";
}
Запустите скрипт:
php send_email.php
Если всё настроено правильно, вы получите письмо на указанный адрес.
4. Основные методы/классы
4.1. Email::class — класс для создания письма
Сигнатура: new Email() (конструктор без параметров)
Что делает: Создает объект письма с методами-сеттерами для настройки всех атрибутов (отправитель, получатель, тема, тело письма, вложения и т.д.).
Пример:
use Symfony\Component\Mime\Email;
$email = (new Email())
->from('sender@example.com')
->to('recipient@example.com')
->cc('cc@example.com')
->bcc('bcc@example.com')
->replyTo('support@example.com')
->priority(Email::PRIORITY_HIGH)
->subject('Важное уведомление')
->text('Текстовая версия')
->html('<h1>HTML версия</h1>');
4.2. Mailer::send() — отправка письма
Сигнатура: public function send(Email $email, ?Envelope $envelope = null): void
Что делает: Отправляет подготовленное письмо через настроенный транспорт. Может выбросить исключение TransportExceptionInterface при ошибке.
Пример:
$mailer->send($email);
4.3. Mailer::sendWithEnvelope() — отправка с конвертом
Сигнатура: public function sendWithEnvelope(Email $email, Envelope $envelope): void
Что делает: Отправляет письмо с явно заданным конвертом (Envelope), что позволяет переопределить адреса отправителя и получателя на транспортном уровне.
Пример:
use Symfony\Component\Mailer\Envelope;
use Symfony\Component\Mime\Address;
$envelope = new Envelope(
new Address('bounce@example.com'),
[new Address('actual-recipient@example.com')]
);
$mailer->sendWithEnvelope($email, $envelope);
4.4. AbstractTransport::send() — низкоуровневая отправка
Сигнатура: abstract protected function doSend(SentMessage $message): void
Что делает: Базовый метод для всех транспортов. Реализует фактическую отправку через SMTP, API или другой протокол. Разработчики редко вызывают его напрямую.
Пример: Используется внутри Mailer::send().
4.5. Transport::fromDsn() — создание транспорта из DSN
Сигнатура: public static function fromDsn(string $dsn, ?HttpClientInterface $client = null, ?EventDispatcherInterface $dispatcher = null): TransportInterface
Что делает: Создает транспорт на основе DSN-строки (например, smtp://user:pass@smtp.example.com:587). Упрощает конфигурацию.
Пример:
use Symfony\Component\Mailer\Transport;
$transport = Transport::fromDsn('smtp://user:pass@smtp.example.com:587?encryption=tls');
$mailer = new Mailer($transport);
4.6. Email::attach() — добавление вложения
Сигнатура: public function attach(string $body, ?string $name = null, ?string $contentType = null): static
Что делает: Добавляет файл к письму в виде вложения. Можно передать содержимое файла, имя и MIME-тип.
Пример:
$email->attach(
file_get_contents('/path/to/document.pdf'),
'document.pdf',
'application/pdf'
);
4.7. Email::embed() — встраивание изображения
Сигнатура: public function embed(string $body, ?string $name = null, ?string $contentType = null): string
Что делает: Встраивает изображение (или другой контент) непосредственно в HTML-тело письма. Возвращает CID (Content-ID), который можно использовать в тегах <img>.
Пример:
$cid = $email->embed(
file_get_contents('/path/to/logo.png'),
'logo.png',
'image/png'
);
$email->html('<img src="cid:' . $cid . '" alt="Logo">');
4.8. Email::addPart() — добавление произвольной MIME-части
Сигнатура: public function addPart(BodyRendererInterface $part): static
Что делает: Добавляет любую MIME-часть к письму (например, календарь iCal, подпись DKIM). Позволяет расширять функциональность письма.
Пример:
use Symfony\Component\Mime\Part\TextPart;
$icalPart = new TextPart(
file_get_contents('/path/to/event.ics'),
'text/calendar; method=REQUEST'
);
$email->addPart($icalPart);
4.9. Mailer::getTransport() — получение текущего транспорта
Сигнатура: public function getTransport(): TransportInterface
Что делает: Возвращает объект транспорта, используемый Mailer'ом. Полезно для отладки или проверки конфигурации.
Пример:
$transport = $mailer->getTransport();
echo get_class($transport); // Например, Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport
4.10. Email::getHeaders() — работа с заголовками
Сигнатура: public function getHeaders(): Headers
Что делает: Возвращает объект Headers, позволяющий добавлять, изменять или удалять произвольные заголовки письма (например, X-Mailer, List-Unsubscribe).
Пример:
$headers = $email->getHeaders();
$headers->addTextHeader('X-Custom-Header', 'MyValue');
$headers->remove('X-Mailer');
5. Реальный практический пример (150+ строк кода)
Рассмотрим пример отправки письма с подтверждением регистрации, включая HTML-шаблон, вложение и логирование. Создадим класс RegistrationMailer:
<?php
// src/Mailer/RegistrationMailer.php
namespace App\Mailer;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\Address;
use Psr\Log\LoggerInterface;
class RegistrationMailer
{
private Mailer $mailer;
private LoggerInterface $logger;
private string $fromEmail;
private string $fromName;
public function __construct(
string $dsn,
LoggerInterface $logger,
string $fromEmail = 'noreply@example.com',
string $fromName = 'Example App'
) {
$transport = Transport::fromDsn($dsn);
$this->mailer = new Mailer($transport);
$this->logger = $logger;
$this->fromEmail = $fromEmail;
$this->fromName = $fromName;
}
/**
* Отправляет письмо с подтверждением регистрации.
*
* @param string $recipientEmail Email получателя
* @param string $recipientName Имя получателя
* @param string $confirmationLink Ссылка для подтверждения
* @param string $attachmentPath Путь к файлу вложения (опционально)
* @return bool true в случае успеха, false при ошибке
*/
public function sendConfirmationEmail(
string $recipientEmail,
string $recipientName,
string $confirmationLink,
?string $attachmentPath = null
): bool {
try {
// Создаем HTML-шаблон письма
$htmlContent = $this->buildHtmlTemplate($recipientName, $confirmationLink);
$textContent = "Здравствуйте, $recipientName!\n\n"
. "Для подтверждения регистрации перейдите по ссылке:\n"
. "$confirmationLink\n\n"
. "С уважением, команда Example App.";
// Формируем письмо
$email = (new Email())
->from(new Address($this->fromEmail, $this->fromName))
->to(new Address($recipientEmail, $recipientName))
->subject('Подтверждение регистрации на Example App')
->text($textContent)
->html($htmlContent)
->priority(Email::PRIORITY_HIGH);
// Добавляем вложение, если указано
if ($attachmentPath !== null && file_exists($attachmentPath)) {
$email->attach(
file_get_contents($attachmentPath),
basename($attachmentPath),
mime_content_type($attachmentPath) ?: 'application/octet-stream'
);
}
// Добавляем кастомный заголовок для отслеживания
$headers = $email->getHeaders();
$headers->addTextHeader('X-Confirmation-Type', 'registration');
// Отправляем
$this->mailer->send($email);
// Логируем успех
$this->logger->info('Confirmation email sent', [
'recipient' => $recipientEmail,
'subject Также в библиотеке
Отправка SMS на Kotlin: API библиотеки smslib4k
WebSocket библиотеки Rust: Tokio-tungstenite и async-tungstenite для реального времени
Работа с Markdown в TypeScript: библиотеки, парсеры и инструменты
resty для Go: полное руководство с примерами
RestSharp для C# (.NET): полное руководство с примерами