dnna/swiftmailer-enqueue-bundle
Symfony bundle that spools SwiftMailer emails to an Enqueue message queue and consumes them via swiftmailer:spool:send. Adds configurable queue options, receive timeouts, graceful shutdown via signal extension, and optional requeue/retry handling.
Installation:
composer require dnna/swiftmailer-enqueue-bundle
Ensure EnqueueBundle is also installed (dependency):
composer require php-enqueue/enqueue-bundle
Enable the Bundle:
Add to config/bundles.php (Symfony 4.4+):
return [
// ...
Enqueue\Bundle\EnqueueBundle::class,
Dnna\SwiftmailerEnqueueBundle\SwiftmailerEnqueueBundle::class,
];
Configure Swiftmailer:
Update config/packages/swiftmailer.yaml to use the enqueue spool:
swiftmailer:
spool: { type: 'enqueue' }
Configure the Bundle:
Add to config/packages/dnna_swiftmailer_enqueue.yaml:
dnna_swiftmailer_enqueue:
queue:
service_id: enqueue.transport.default.context # Default Enqueue transport
key: swiftmailer_spool
requeue_on_exception: true
max_requeue_attempts: 3
Start Consuming Emails: Run the consumer in a separate process (e.g., via Supervisor or Docker):
php bin/console swiftmailer:spool:consume
Note: This command is blocking—run it in the background.
Decouple Email Sending from HTTP Requests: Replace synchronous Swiftmailer with an async queue to improve response times. Example:
// In a Laravel controller (using Symfony's Swiftmailer via Laravel's Mail facade)
Mail::to('user@example.com')->send(new WelcomeEmail());
// Emails are now queued via Enqueue, not sent immediately.
Spooling Emails:
config/packages/enqueue.yaml:
enqueue:
client:
transport: redis://localhost
Consuming Emails:
php bin/console swiftmailer:spool:consume --time-limit=300
--limit=100 # Process 100 messages max
--timeout=60 # Timeout in seconds
--verbose # Debug output
Graceful Shutdown:
config/packages/dnna_swiftmailer_enqueue.yaml:
dnna_swiftmailer_enqueue:
consumption:
signal_extension: true
Laravel-Specific Setup:
Mail facade with Symfony’s Swiftmailer, ensure the bundle is loaded after Laravel’s Swiftmailer configuration:
// config/app.php
'providers' => [
// ...
Swiftmailer\SwiftmailerServiceProvider::class,
],
config/mail.php:
'spool' => [
'driver' => 'enqueue',
],
Queue Monitoring:
php bin/console enqueue:consume --queue=swiftmailer_spool
php bin/console enqueue:stats
Error Handling:
dnna_swiftmailer_enqueue:
queue:
service_id: enqueue.transport.dlq.context
Testing:
$this->app->make('enqueue.transport.default.context')->method('send')->willReturn(true);
Blocking Command:
swiftmailer:spool:send is blocking by design. Avoid running it in development unless necessary. Use --time-limit to prevent hangs:
php bin/console swiftmailer:spool:send --time-limit=10
Transport Configuration:
php bin/console enqueue:setup:transport
Requeue Logic:
requeue_on_exception defaults to false. Set to true to retry failed emails, but beware of infinite loops with max_requeue_attempts (default: 5).Signal Handling:
signal_extension requires a non-blocking environment (e.g., Docker or Supervisor). Test with:
kill -SIGTERM <process_id>
Consumer Logs:
php bin/console swiftmailer:spool:consume --verbose
var/log/dev.log) for errors.Queue Inspection:
php bin/console enqueue:consume --queue=swiftmailer_spool --limit=1
Common Errors:
key in dnna_swiftmailer_enqueue matches the queue name.var/spool).Custom Transports:
# config/services.yaml
services:
App\Swiftmailer\CustomTransport:
arguments:
$transport: '@enqueue.transport.custom.context'
Then bind it to the bundle’s service_id.Event Listeners:
SentEvent) to log or modify emails:
use Symfony\Component\Swiftmailer\Event\SentEvent;
$eventDispatcher->addListener(SentEvent::NAME, function (SentEvent $event) {
// Custom logic (e.g.,
How can I help you explore Laravel packages today?