What is Symfony mailer

Valerio Barbera

Symfony Mailer is a PHP library for sending transactinal emails. It replaces SwiftMailer, offering better performance, simpler configuration, and modern features for email handling in Symfony applications.

Key Features:

  • Twig Integration: Create dynamic email templates.
  • CSS Inlining: Ensures compatibility across email clients.
  • Transport Layer: Supports multiple email providers like Mailgun, SendGrid, and Amazon SES.
  • Messenger Support: Enables asynchronous email sending for better performance.

Why Use Symfony Mailer?

Symfony Mailer

  • Smaller email payloads (2kB vs 16kB with SwiftMailer).
  • Reduces boilerplate code by 40%.
  • Handles up to 350,000 emails per hour per core.
  • Built-in support for SPF/DKIM and secure email delivery.

Whether you’re sending basic emails or managing complex queues with Symfony Messenger, Symfony Mailer simplifies the process while ensuring reliability and scalability.

Setup and Configuration

Getting the setup right is key to ensuring secure email delivery.

Installation Steps

First, install Symfony Mailer using Composer:

composer require symfony/mailer

Email Settings

You’ll need to configure your email transport by setting the MAILER_DSN in your .env file. The format depends on your email provider:

Provider MAILER_DSN Format Notes
SMTP smtp://user:[email protected]:port
Gmail gmail://USERNAME:PASSWORD@default Requires app-specific password
Mailgun mailgun://KEY:DOMAIN@default

Key security tips:

  • Store credentials as server environment variables.
  • Use smtps:// for encrypted connections.
  • Ensure SPF/DKIM records are properly configured.

Local Email Testing

For local testing, you can use Mailhog to capture emails without sending them to real addresses:

  1. Run Mailhog, which is accessible at localhost:8025.
  2. Update your .env.local file with the following:
    MAILER_DSN=smtp://localhost:1025
    

“For local development, Mailhog provides the most reliable way to test email functionality without risking accidental sends to real addresses” [3]

To confirm your setup, create a test route and use this basic email script:

public function testMail(MailerInterface $mailer): Response {
    $mailer->send((new Email())
        ->from('[email protected]')
        ->to('[email protected]')
        ->subject('Test Email')
        ->text('Configuration working!'));
    return new Response('Email sent');
}

Check the Mailhog interface to verify the email was delivered successfully. Once your setup is complete, you’re ready to start implementing email-sending features.

Sending Emails

Symfony Mailer makes it easy to send both simple and more detailed emails. Here’s how you can handle different email scenarios effectively.

Basic Email Setup

To send an email, you can use MailerInterface along with the Email class. Here’s a basic example:

use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;

public function sendEmail(MailerInterface $mailer)
{
    try {
        // Add your email-sending logic here
    } catch (TransportExceptionInterface $e) {
        $this->logger->error('Email failed: '.$e->getMessage());
        throw new \Exception('Failed to send email');
    }
}

HTML Emails and Attachments

To maintain a professional look, you can use the TemplatedEmail class, which works well with Twig templates:

use Symfony\Bridge\Twig\Mime\TemplatedEmail;

$email = (new TemplatedEmail())
    ->htmlTemplate('emails/notification.html.twig')
    ->context([
        'username' => $user->getName(),
        'expiration_date' => new \DateTime('+7 days')
    ]);

This allows you to send HTML-based emails with dynamic content, ensuring a polished appearance.

User Registration Email

Here’s a more detailed example for sending a registration confirmation email:

public function register(User $user, MailerInterface $mailer)
{
    $email = (new TemplatedEmail())
        ->from(new Address('[email protected]', 'App Bot'))
        ->to(new Address($user->getEmail(), $user->getName()))
        ->subject('Welcome to Our Platform')
        ->htmlTemplate('emails/registration.html.twig')
        ->context([
            'user' => $user,
            'verification_url' => $this->generateUrl('verify_email', [
                'token' => $user->getVerificationToken()
            ])
        ]);

    try {
        $mailer->send($email);
    } catch (TransportExceptionInterface $e) {
        $this->logger->error('Registration email failed: '.$e->getMessage());
        // Handle the error appropriately
    }
}

Twig Template Example:

<h1>Welcome {{ user.name }}!</h1>
<p>Please confirm your account by clicking the link below:</p>
<a href="{{ verification_url }}">Confirm Account</a>

Additional Configuration for HTML Emails

To improve email compatibility across different clients, enable the CSS inliner in your mailer.yaml configuration:

framework:
    mailer:
        html_to_text_converter: 'css_to_inline_styles'

For situations like sending many emails (e.g., user registrations), you might want to queue emails for better performance. This approach ensures reliability even under heavy loads.

Queue-Based Email Sending

To implement asynchronous email sending during user registrations, Symfony Messenger offers an efficient solution. This approach helps avoid performance issues and ensures emails are sent reliably.

Adding Symfony Messenger

Symfony Messenger

First, install Symfony Messenger via Composer:

composer require symfony/messenger

Next, update your email sending service to leverage MessageBusInterface for dispatching email messages:

use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Mailer\Messenger\SendEmailMessage;

class EmailService
{
    private $bus;

    public function __construct(MessageBusInterface $bus)
    {
        $this->bus = $bus;
    }

    public function sendWelcomeEmail(User $user)
    {
        $email = (new TemplatedEmail())
            ->from('[email protected]')
            ->to($user->getEmail())
            ->subject('Welcome!')
            ->htmlTemplate('emails/welcome.html.twig');

        $this->bus->dispatch(new SendEmailMessage($email));
        // SendEmailMessage is part of the Symfony Mailer component
    }
}

Configuring the Queue

Set up your message transport in config/packages/messenger.yaml:

framework:
    messenger:
        transports:
            async_emails:
                dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
                retry_strategy:
                    max_retries: 3
                    delay: 1000
        routing:
            'Symfony\Component\Mailer\Messenger\SendEmailMessage': async_emails

Here’s a quick guide to transport types and their use cases:

Transport Type Configuration Example Best Use Case
Doctrine doctrine://default Development or small-scale applications
Redis redis://localhost:6379/messages Medium-load production environments
RabbitMQ amqp://user:pass@localhost:5672/%2f/messages High-traffic production setups

Processing the Queue

Start processing queued emails by running the following command:

php bin/console messenger:consume async_emails -vv

For production environments, set up a supervisor configuration to keep the worker running:

[program:symfony-messenger]
command=php /var/www/project/bin/console messenger:consume async_emails --time-limit=3600
user=www-data
numprocs=2
autostart=true
autorestart=true

“The queue-based approach using Symfony Messenger reduces 500 errors by 72% in high-traffic scenarios according to Symfony best practices docs”

Monitoring the Queue

Symfony Messenger includes tools to monitor and manage your email queue:

# Check queue statistics
php bin/console messenger:stats

# View failed messages
php bin/console messenger:failed:show

These commands help ensure your queue is running smoothly and troubleshoot any issues.

sbb-itb-f1cefd0

Queue Management

Effectively managing email queues is key to ensuring smooth and reliable message delivery in Symfony Mailer. Here’s a breakdown of the essentials for handling queues and keeping everything running smoothly.

Error Recovery

Symfony’s built-in retry strategy ensures failed email deliveries are addressed automatically. It can handle issues like network problems or server timeouts without requiring manual intervention.

For more persistent failures, you can set up a dead letter queue in your messenger configuration. Here’s an example:

framework:
    messenger:
        failure_transport: failed
        transports:
            failed: 'doctrine://default?queue_name=failed'

This configuration enables you to:

  • Retry failed messages up to three times
  • Store problematic messages for manual inspection
  • Log failure details for analysis
  • Develop tailored recovery solutions

Inspector.dev Integration

Inspector.dev

Symfony offers basic tools for monitoring, but services like Inspector.dev bring advanced capabilities like real-time alerts and detailed performance insights. Once you’ve installed the Inspector package (composer require inspector-apm/inspector-symfony).

You just need to add the Ingestion Key to your environment file to start monitoring your application:

INSPECTOR_INGESTION_KEY=b8de37c3xxxxxxxxxxxxxxxxxxxxxxxxxxxx

With Inspector.dev, you gain access to metrics such as message throughput, failure trends, and delivery latency, all in a centralized dashboard.

Direct vs Queued Email Delivery

Choosing between direct sending and queue-based email delivery depends on your needs. Here’s a quick comparison:

Aspect Direct Sending Queue-Based Sending
Response Time Immediate delivery attempt Deferred processing
Server Load Higher immediate resource use Distributed over time
Error Handling Instant feedback on issues Advanced retry mechanisms
Scalability Limited by server capacity Scales with infrastructure
Impact on App Can slow user requests Minimal effect on app

“Queue-based sending using Symfony Messenger reduces server load by up to 70% during peak email sending periods, according to Symfony’s performance benchmarks”.

To manage the rate at which queued emails are processed, you can extend the messenger transport configuration with rate limits:

framework:
    messenger:
        transports:
            async_emails:
                dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
                options:
                    rate_limit: 
                        count: 100
                        interval: '1 minute'

This setup ensures your email system remains efficient and avoids overloading resources during high-traffic periods.

Summary

Let’s recap the key features of Symfony Mailer and its benefits for email handling:

Symfony Mailer offers a modern approach to managing emails, including:

  • Support for various transports like SMTP, sendmail, and API services
  • HTML email creation with Twig integration
  • Built-in support for DKIM and SPF
  • Easy handling of attachments
  • Seamless integration with popular email services

Impressively, it can handle up to 350,000 emails per hour per core.

When paired with Messenger, Symfony Mailer becomes a complete email solution. This integration allows for:

  • Background email processing without impacting app performance
  • Scalability to handle large volumes
  • Reliable error recovery mechanisms
  • Efficient resource management

Next Steps

To maximize these features in a production environment, consider the following:

  1. Use monitoring tools like Inspector.dev for tracking and managing your queues.
  2. Set up rate limits as outlined in the queue configuration examples.
  3. Scale workers and add dead letter queues to ensure reliable email delivery.

Monitoring tools like Inspector.dev can help you keep an eye on:

  • Queue performance
  • Worker activity
  • Failed messages
  • Resource usage

FAQs

How do I replace SwiftMailer with Symfony Mailer?

Here’s a quick guide to make the switch:

  • Remove SwiftMailer: Run the following command to uninstall SwiftMailer:
    composer remove symfony/swiftmailer-bundle
    
  • Install Symfony Mailer: Add the Symfony Mailer package:
    composer require symfony/mailer
    
  • Update Configurations: Adjust your configuration files to use MAILER_DSN.
  • Refactor Code: Replace all Swift_Message instances with Email or TemplatedEmail.

For detailed steps, check the Email Settings section mentioned earlier.

What is Symfony Mailer?

Symfony Mailer is a powerful tool for creating and sending emails in Symfony applications. It replaces SwiftMailer and offers better performance – handling up to 350,000 emails per hour per core. It also includes modern features like CSS inlining and DKIM support.

Key features include:

  • Support for multiple transport methods
  • HTML templates for emails
  • High performance for large-scale applications

You can also integrate it with Messenger to send emails through a queue, as explained in the Queue Configuration section. These capabilities make it a reliable choice for managing email functionality in your projects.

Related Blog Posts

Related Posts

Managing Human-in-the-Loop With Checkpoints – Neuron Workflow

The integration of human oversight into AI workflows has traditionally been a Python-dominated territory, leaving PHP developers to either compromise on their preferred stack or abandon sophisticated agentic patterns altogether. The new checkpointing feature in Neuron’s Workflow component continues to strengthen the dynamic of bringing production-ready human-in-the-loop capabilities directly to PHP environments. Checkpointing addresses a

Monitor Your PHP Applications Through Your AI Assistant – Inspector MCP server

You push code, hope it works, and discover issues when users complain or error rates spike. Traditional monitoring tools require constant context switching—jumping between your IDE, terminal, dashboard tabs, and documentation. This friction kills productivity and delays problem resolution. Inspector’s new MCP server changes this dynamic by connecting your AI coding assistant directly to your

High-Perfomance Tokenizer in PHP

When I launched Neuron AI Framework six months ago, I wasn’t certain PHP could compete with Python’s AI ecosystem. The framework’s growth to over 1,000 GitHub stars in five months changed that perspective entirely. What began as an experiment in bringing modern AI agents capabilities to PHP has evolved into something more substantial: proof that