Mailer Component
Symfony 8.0: Компоненты Mailer и Mime явно указаны в темах экзамена.
Mailer -- компонент для отправки email. Поддерживает различные транспорты (SMTP, Sendmail, API-провайдеры).
Конфигурация
# config/packages/mailer.yaml
framework:
mailer:
dsn: '%env(MAILER_DSN)%'
# .env
MAILER_DSN=smtp://user:[email protected]:465
Основные DSN
| Провайдер | DSN |
|---|---|
| SMTP | smtp://user:[email protected]:587 |
| Gmail | gmail+smtp://user:pass@default |
| Sendmail | sendmail://default |
| Null (тесты) | null://null |
Mime Component и Email
Mime component создаёт email-сообщения.
Простой email
<?php
declare(strict_types=1);
namespace App\Service;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
final class NotificationService
{
public function __construct(
private readonly MailerInterface $mailer,
) {
}
public function sendWelcome(string $to, string $name): void
{
$email = (new Email())
->from('[email protected]')
->to($to)
->subject('Welcome to Our Platform!')
->text("Hello $name, welcome to our platform!")
->html("<h1>Hello $name!</h1><p>Welcome to our platform!</p>");
$this->mailer->send($email);
}
}
Email с вложениями
<?php
declare(strict_types=1);
namespace App\Service;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\Part\DataPart;
use Symfony\Component\Mime\Part\File;
final class InvoiceMailer
{
public function __construct(
private readonly MailerInterface $mailer,
) {
}
public function sendInvoice(
string $to,
string $invoiceNumber,
string $pdfPath,
): void {
$email = (new Email())
->from('[email protected]')
->to($to)
->cc('[email protected]')
->bcc('[email protected]')
->replyTo('[email protected]')
->priority(Email::PRIORITY_HIGH)
->subject("Invoice #{$invoiceNumber}")
->text("Please find your invoice attached.")
->html('<p>Please find your invoice attached.</p>')
// File attachment
->attachFromPath($pdfPath, "invoice-{$invoiceNumber}.pdf")
// Inline attachment (embed in HTML)
->embedFromPath('/path/to/logo.png', 'logo')
->html('<img src="cid:logo"> <p>Your invoice is attached.</p>')
// Data attachment (from string)
->attach(
$csvContent,
"invoice-{$invoiceNumber}.csv",
'text/csv',
);
$this->mailer->send($email);
}
}
Email с адресами
<?php
declare(strict_types=1);
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
$email = (new Email())
// Simple address
->from('[email protected]')
// Address with name
->from(new Address('[email protected]', 'John Doe'))
// Multiple recipients
->to('[email protected]', '[email protected]')
->to(new Address('[email protected]', 'User Three'))
->cc('[email protected]')
->bcc('[email protected]')
->replyTo('[email protected]')
->subject('Test Email');
Twig Integration (TemplatedEmail)
<?php
declare(strict_types=1);
namespace App\Service;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
final class OrderMailer
{
public function __construct(
private readonly MailerInterface $mailer,
) {
}
public function sendOrderConfirmation(Order $order): void
{
$email = (new TemplatedEmail())
->from(new Address('[email protected]', 'MyShop'))
->to($order->getCustomerEmail())
->subject("Order #{$order->getNumber()} Confirmation")
// Twig template for HTML
->htmlTemplate('emails/order_confirmation.html.twig')
// Variables passed to template
->context([
'order' => $order,
'items' => $order->getItems(),
'customer_name' => $order->getCustomerName(),
]);
$this->mailer->send($email);
}
}
Twig-шаблон email
{# templates/emails/order_confirmation.html.twig #}
{% extends 'emails/base.html.twig' %}
{% block subject %}Order #{{ order.number }} Confirmation{% endblock %}
{% block body %}
<h1>Thank you, {{ customer_name }}!</h1>
<p>Your order #{{ order.number }} has been confirmed.</p>
<table>
<thead>
<tr>
<th>Product</th>
<th>Qty</th>
<th>Price</th>
</tr>
</thead>
<tbody>
{% for item in items %}
<tr>
<td>{{ item.name }}</td>
<td>{{ item.quantity }}</td>
<td>{{ item.price|format_currency('USD') }}</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="2"><strong>Total:</strong></td>
<td><strong>{{ order.total|format_currency('USD') }}</strong></td>
</tr>
</tfoot>
</table>
{% endblock %}
Async Email с Messenger
Отправка email может быть медленной. Messenger позволяет отправлять email асинхронно.
# config/packages/messenger.yaml
framework:
messenger:
transports:
async: '%env(MESSENGER_TRANSPORT_DSN)%'
routing:
# Route email messages to async transport
'Symfony\Component\Mailer\Messenger\SendEmailMessage': async
Теперь все вызовы $mailer->send() автоматически отправляют сообщение в очередь. Worker обработает его асинхронно.
<?php
declare(strict_types=1);
// This is automatic! Just route SendEmailMessage to async transport.
// No changes to your code needed:
$this->mailer->send($email);
// Email goes to Messenger queue, not sent immediately
Email Events
<?php
declare(strict_types=1);
namespace App\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Mailer\Event\MessageEvent;
final class EmailSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
MessageEvent::class => 'onMessage',
];
}
public function onMessage(MessageEvent $event): void
{
$message = $event->getMessage();
// Add custom header to every email
$message->getHeaders()->addTextHeader(
'X-Application',
'MyApp',
);
}
}
Итоги
- Mailer отправляет email через настроенный транспорт (SMTP, API)
Email-- простой email,TemplatedEmail-- с Twig-шаблоном- Вложения:
attachFromPath(),attach(),embedFromPath() Address-- адрес с именем- Async через Messenger: роутинг
SendEmailMessageв async transport MessageEvent-- событие для модификации всех исходящих email