# Symfony Mailer Symfony Mailer is a powerful PHP component for sending emails with support for multiple transport protocols including SMTP, Sendmail, and third-party providers. It provides a clean, object-oriented API for composing and delivering email messages with features like transport failover, rate limiting, and event-driven message manipulation. The component integrates seamlessly with the Symfony ecosystem but can be used standalone in any PHP application. The Mailer component supports both synchronous and asynchronous email delivery through Symfony Messenger integration. It provides extensible transport architecture allowing DSN-based configuration, DKIM signing, S/MIME encryption, and Twig template rendering for HTML emails. The event system enables pre-send manipulation of messages and envelopes, while test utilities simplify email assertions in automated tests. ## Creating and Sending Basic Emails The Mailer class sends email messages using a configured transport. Create an Email instance with recipients, subject, and body content, then pass it to the mailer's send method. ```php from('sender@example.com') ->to('recipient@example.com') ->cc('cc@example.com') ->bcc('bcc@example.com') ->replyTo('reply@example.com') ->priority(Email::PRIORITY_HIGH) ->subject('Important Notification') ->text('Plain text email body') ->html('

HTML Email

Rich content with formatting.

'); // Send the email $mailer->send($email); ``` ## Configuring Transports with DSN The Transport class creates transport instances from DSN (Data Source Name) strings. DSN configuration supports various protocols and options for flexible email delivery setup. ```php getScheme(); // 'smtp' echo $dsn->getHost(); // 'mail.example.com' echo $dsn->getPort(); // 587 echo $dsn->getUser(); // 'user' echo $dsn->getPassword(); // 'secret' echo $dsn->getOption('timeout'); // '30' ``` ## Using ESMTP Transport with Authentication The EsmtpTransport class provides full ESMTP support with multiple authentication mechanisms (CRAM-MD5, LOGIN, PLAIN, XOAUTH2), automatic TLS negotiation, and configurable security options. ```php setUsername('smtp_user'); $transport->setPassword('smtp_password'); // Configure TLS settings $transport->setAutoTls(true); // Enable automatic STARTTLS $transport->setRequireTls(true); // Require TLS connection // Set rate limiting (emails per second) $transport->setMaxPerSecond(10); // Send email $email = (new Email()) ->from('noreply@example.com') ->to('user@example.com') ->subject('Account Verification') ->html('

Please verify your email address.

'); $sentMessage = $transport->send($email); // Access sent message details echo $sentMessage->getMessageId(); echo $sentMessage->getDebug(); ``` ## Configuring Failover and Round-Robin Transports Multiple transports can be combined using FailoverTransport (automatic fallback on failure) or RoundRobinTransport (load distribution) for high availability email delivery. ```php from('system@example.com') ->to('admin@example.com') ->subject('System Notification') ->text('Load-balanced email delivery'); $mailer->send($email); ``` ## Using Named Transports with X-Transport Header The Transports class manages multiple named transports, allowing runtime selection via the X-Transport header. This enables different delivery methods for different email types. ```php $transactional, 'marketing' => $marketing, 'internal' => $internal, ]); $mailer = new Mailer($transports); // Send via specific transport using X-Transport header $email = (new Email()) ->from('newsletters@example.com') ->to('subscriber@example.com') ->subject('Weekly Newsletter') ->text('Newsletter content here'); $email->getHeaders()->addTextHeader('X-Transport', 'marketing'); $mailer->send($email); // Default transport used when no X-Transport specified $orderConfirmation = (new Email()) ->from('orders@example.com') ->to('customer@example.com') ->subject('Order Confirmed') ->text('Your order has been confirmed.'); $mailer->send($orderConfirmation); // Uses 'transactional' (first defined) ``` ## Working with Email Envelopes The Envelope class controls the actual SMTP envelope sender and recipients, which can differ from the message headers (From/To). This is useful for bounce handling and recipient management. ```php from('noreply@example.com') // Displayed in email client ->to('recipient1@example.com') ->subject('Important Update') ->text('Message content'); // Envelope overrides actual delivery $mailer->send($email, $envelope); // Create envelope from message automatically $autoEnvelope = Envelope::create($email); echo $autoEnvelope->getSender()->getAddress(); // Check for Unicode localparts (SMTPUTF8 support) $hasUnicode = $envelope->anyAddressHasUnicodeLocalpart(); ``` ## Handling Message Events The event system allows manipulation of messages before sending. Subscribe to MessageEvent to modify content, headers, or reject emails based on custom logic. ```php addListener(MessageEvent::class, function (MessageEvent $event) { $message = $event->getMessage(); if ($message instanceof Email) { // Add tracking header $message->getHeaders()->addTextHeader('X-Campaign-ID', 'spring-2024'); // Modify envelope recipients $envelope = $event->getEnvelope(); // Reject spam-like messages if (str_contains($message->getSubject() ?? '', 'URGENT!!!')) { $event->reject(); return; } } // Check if message is queued for async delivery if ($event->isQueued()) { // Add Messenger stamps for queued messages // $event->addStamp(new SomeStamp()); } }); // Log successful sends $dispatcher->addListener(SentMessageEvent::class, function (SentMessageEvent $event) { $sentMessage = $event->getMessage(); error_log('Email sent: ' . $sentMessage->getMessageId()); }); // Handle failures $dispatcher->addListener(FailedMessageEvent::class, function (FailedMessageEvent $event) { $error = $event->getError(); error_log('Email failed: ' . $error->getMessage()); }); $transport = Transport::fromDsn('smtp://localhost', $dispatcher); $mailer = new Mailer($transport, null, $dispatcher); $email = (new Email()) ->from('app@example.com') ->to('user@example.com') ->subject('Welcome!') ->text('Welcome to our platform.'); $mailer->send($email); ``` ## Using EnvelopeListener for Global Sender/Recipient Control EnvelopeListener automatically overrides envelope settings globally, useful for development environments or centralized bounce handling. ```php addSubscriber($listener); $transport = Transport::fromDsn('smtp://localhost', $dispatcher); $mailer = new Mailer($transport, null, $dispatcher); // All emails redirected to dev-testing@example.com $email = (new Email()) ->from('app@example.com') ->to('real-customer@example.com') // Will be overridden ->cc('manager@example.com') // Will be overridden ->subject('Order Confirmation') ->text('Your order details...'); $mailer->send($email); ``` ## Using MessageListener for Default Headers and Template Rendering MessageListener sets default headers and integrates with Twig for template-based email rendering. ```php addMailboxHeader('From', 'noreply@example.com'); $defaultHeaders->addMailboxListHeader('Bcc', ['archive@example.com']); $defaultHeaders->addTextHeader('X-Mailer', 'MyApp/1.0'); $dispatcher = new EventDispatcher(); // Configure listener with header rules $listener = new MessageListener( $defaultHeaders, $bodyRenderer, [ 'from' => MessageListener::HEADER_SET_IF_EMPTY, 'bcc' => MessageListener::HEADER_ADD, 'x-mailer' => MessageListener::HEADER_REPLACE, ] ); $dispatcher->addSubscriber($listener); $transport = Transport::fromDsn('smtp://localhost', $dispatcher); $mailer = new Mailer($transport, null, $dispatcher); // Send templated email $email = (new TemplatedEmail()) ->to('user@example.com') ->subject('Welcome, {{ username }}!') ->htmlTemplate('emails/welcome.html.twig') ->context([ 'username' => 'John', 'activation_link' => 'https://example.com/activate/abc123', ]); $mailer->send($email); ``` ## DKIM Signing Messages DkimSignedMessageListener automatically signs outgoing messages with DKIM for email authentication and deliverability. ```php addSubscriber($listener); $transport = Transport::fromDsn('smtp://localhost', $dispatcher); $mailer = new Mailer($transport, null, $dispatcher); // Emails are automatically DKIM-signed $email = (new Email()) ->from('noreply@example.com') ->to('recipient@example.com') ->subject('Authenticated Message') ->text('This email is signed with DKIM.'); $mailer->send($email); ``` ## Asynchronous Email Delivery with Messenger The Mailer integrates with Symfony Messenger for asynchronous email delivery, improving application response times by queuing emails for background processing. ```php [$messageHandler], ])), ]); // Create mailer with bus for async delivery $mailer = new Mailer($transport, $bus, $dispatcher); // Email is dispatched to bus instead of sent immediately $email = (new Email()) ->from('app@example.com') ->to('user@example.com') ->subject('Background Task Complete') ->text('Your export is ready for download.'); $mailer->send($email); // Process queue manually (normally done by messenger:consume command) // The handler will call $transport->send() when processing the message ``` ## Using Custom Headers for Metadata and Tags MetadataHeader and TagHeader provide standardized ways to add tracking information and tags to emails for analytics and filtering. ```php from('marketing@example.com') ->to('subscriber@example.com') ->subject('Special Offer Inside!') ->text('Check out our latest deals.'); // Add metadata (creates X-Metadata-* headers) $email->getHeaders()->add(new MetadataHeader('campaign-id', 'summer-sale-2024')); $email->getHeaders()->add(new MetadataHeader('user-segment', 'premium')); // Add tags (creates X-Tag header) $email->getHeaders()->add(new TagHeader('promotional')); $email->getHeaders()->add(new TagHeader('newsletter')); $mailer->send($email); ``` ## Testing Email Functionality The Test namespace provides PHPUnit constraints for asserting email behavior in automated tests. ```php addSubscriber($logger); // Use null transport for testing $transport = Transport::fromDsn('null://null', $dispatcher); $mailer = new Mailer($transport, null, $dispatcher); // Send test email $email = (new Email()) ->from('test@example.com') ->to('user@example.com') ->subject('Test Email') ->text('Test content'); $mailer->send($email); // Assert email count $events = $logger->getEvents(); $this->assertThat($events, new EmailCount(1)); // Assert on specific transport $this->assertThat($events, new EmailCount(1, 'null://')); // Check queued vs sent $this->assertThat($events, new EmailCount(1, null, false)); // sent } } ``` ## Console Command for Testing Transports The MailerTestCommand provides a CLI tool to verify transport configuration by sending test emails. ```bash # Basic usage - send test email php bin/console mailer:test recipient@example.com # Customize sender and content php bin/console mailer:test recipient@example.com \ --from=sender@example.com \ --subject="Test from staging" \ --body="Verifying email configuration" # Test specific named transport php bin/console mailer:test recipient@example.com --transport=marketing ``` ```php add($command); $application->run(); ``` ## Sendmail Transport Configuration SendmailTransport sends emails through the local sendmail binary, supporting both interactive (-bs) and non-interactive (-t) modes. ```php from('server@example.com') ->to('admin@example.com') ->subject('Server Alert') ->text('Disk usage is above 90%'); $mailer->send($email); ``` ## Summary Symfony Mailer excels in enterprise applications requiring reliable email delivery with high availability through failover and round-robin transport configurations. The DSN-based setup simplifies configuration management across environments, while the event-driven architecture enables powerful customizations like DKIM signing, envelope manipulation, and message filtering. Integration with Symfony Messenger provides non-blocking email delivery essential for high-performance web applications. The component's testing utilities make it straightforward to verify email functionality in automated test suites without sending actual emails. For production deployments, the combination of multiple transport backends, rate limiting, automatic TLS negotiation, and comprehensive error handling ensures reliable email delivery. The modular design allows developers to start with simple SMTP configuration and progressively add features like template rendering, encryption, and analytics tracking as requirements evolve.