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?

- 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:
- Run Mailhog, which is accessible at
localhost:8025. - Update your
.env.localfile 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

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

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:
- Use monitoring tools like Inspector.dev for tracking and managing your queues.
- Set up rate limits as outlined in the queue configuration examples.
- 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_Messageinstances withEmailorTemplatedEmail.
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.


