94noni/swiftmailer-bundle
Fork of Symfony Swiftmailer Bundle with Symfony 6+ support (tagged v4). Intended for personal projects needing Swiftmailer, especially for sending emails from CLI commands where Symfony Mailer may not work for specific use cases.
Install the Package
Add the package to your composer.json:
composer require 94noni/swiftmailer-bundle
Ensure your project uses Symfony 6+ and PHP 8.1+.
Configure Swiftmailer
Update your config/packages/swiftmailer.yaml (or equivalent Laravel config) to match Symfony’s Swiftmailer setup:
framework:
mailer:
dsn: '%env(MAILER_DSN)%'
# Example: 'smtp://user:pass@smtp.example.com:port'
First Use Case: Sending Emails from CLI
Use Symfony’s Mailer component directly in a Laravel Artisan command:
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
class SendTestEmailCommand extends Command
{
protected static $defaultName = 'app:send-test-email';
public function handle(MailerInterface $mailer)
{
$email = (new Email())
->from('sender@example.com')
->to('recipient@example.com')
->subject('Test Email')
->text('Hello from Swiftmailer!');
$mailer->send($email);
$this->info('Email sent!');
}
}
Register the command in app/Console/Kernel.php:
protected $commands = [
\App\Console\Commands\SendTestEmailCommand::class,
];
Verify Configuration Run the command to test:
php artisan app:send-test-email
Dependency Injection (DI) Integration Leverage Symfony’s DI container in Laravel by binding services explicitly or using autowiring:
// In a Laravel service provider (e.g., AppServiceProvider)
$this->app->bind(MailerInterface::class, function ($app) {
return new Mailer(
new Transport($app['config']['mailer.dsn'])
);
});
Reusable Email Templates
Create reusable email templates using Symfony’s Email class:
// app/Services/EmailService.php
class EmailService
{
public function sendWelcomeEmail(MailerInterface $mailer, string $email, string $name)
{
$email = (new Email())
->from('noreply@example.com')
->to($email)
->subject("Welcome, $name!")
->html($this->renderTemplate('welcome.html.twig', ['name' => $name]));
$mailer->send($email);
}
private function renderTemplate(string $template, array $data): string
{
// Use Twig or Laravel Blade to render templates
return view($template, $data)->render();
}
}
Async Email Processing
Use Symfony’s AsyncMailer for background email sending (requires a message queue like Symfony Messenger):
# config/packages/messenger.yaml
framework:
messenger:
transports:
async: '%env(MESSENGER_TRANSPORT_DSN)%'
routing:
'Symfony\Component\Mailer\Messenger\SendEmailMessage': async
Testing Emails
Mock the MailerInterface in PHPUnit tests:
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
public function testSendEmail()
{
$mailer = $this->createMock(MailerInterface::class);
$mailer->expects($this->once())
->method('send')
->with($this->isInstanceOf(Email::class));
$this->app->instance(MailerInterface::class, $mailer);
// Test your email-sending logic here
}
CLI-Driven Email Workflows Use Artisan commands for bulk email operations (e.g., newsletters):
class SendNewsletterCommand extends Command
{
protected static $defaultName = 'app:send-newsletter';
public function handle(MailerInterface $mailer, UserRepository $users)
{
$users->all()->each(function ($user) use ($mailer) {
$mailer->send($this->createNewsletterEmail($user));
});
}
private function createNewsletterEmail(User $user): Email
{
// ...
}
}
Event-Driven Emails Trigger emails from Laravel events (e.g., user registration):
// In an event listener
public function handle(UserRegistered $event)
{
$mailer = app(MailerInterface::class);
$mailer->send($this->createWelcomeEmail($event->user));
}
Attachment Handling Attach files dynamically:
$email = (new Email())
->attachFromPath('/path/to/file.pdf')
->embed($this->mailer->embedFromPath('/path/to/image.png'))
->html('Check the <img src="cid:image.png"> and <a href="cid:file.pdf">attachment</a>.');
Laravel-Symfony Hybrid Projects If your project mixes Laravel and Symfony, ensure consistent configuration:
Mailer component as the single source of truth for email logic.Mail facade and Symfony’s Mailer.Queue Integration
For Laravel queue workers, ensure Symfony’s AsyncMailer is properly configured with a queue adapter (e.g., Redis, Doctrine):
# config/packages/messenger.yaml
framework:
messenger:
transports:
async: 'doctrine://default'
routing:
'Symfony\Component\Mailer\Messenger\SendEmailMessage': async
Logging and Debugging Enable Symfony’s mail logging for debugging:
# config/packages/monolog.yaml
monolog:
handlers:
mail:
type: stream
path: '%kernel.logs_dir%/%kernel.environment%.mail.log'
level: debug
channels: ['mailer']
Environment-Specific Configs Use Laravel’s environment configs to switch between development/staging/production:
# .env
MAILER_DSN=smtp://user:pass@smtp.example.com:587?encryption=tls&authmode=login
# config/packages/swiftmailer.yaml
framework:
mailer:
dsn: '%env(MAILER_DSN)%'
Symfony 6+ Breaking Changes
// Example: Explicit binding for a custom transport
$this->app->bind(TransportInterface::class, function () {
return new DsnTransport('%env(MAILER_DSN)%');
});
Swift_Events) may be removed. Update to Symfony’s Mailer events instead.PHP 8.1+ Requirements
array|string), which may cause type errors in older PHP.Laravel-Specific Quirks
Mail facade alongside Symfony’s Mailer, ensure no duplicate configurations exist.AsyncMailer may not integrate seamlessly with Laravel’s queue system out of the box. Test thoroughly.Configuration Overrides
config/mail.php may conflict with Symfony’s swiftmailer.yaml. Prioritize Symfony’s config for consistency:
# config/packages/swiftmailer.yaml
framework:
mailer:
dsn: '%env(MAILER_DSN)%'
# Override Laravel's mail config here
Event Listener Conflicts
MailerEvents (e.g., SentEvent) may not trigger Laravel’s MailSent events. Use Symfony’s event system exclusively for mail-related events.Email Not Sending?
%env(MAILER_DSN)% is correctly set in .env.php bin/console debug:mailer:transport
How can I help you explore Laravel packages today?