sylius/mailer
Sylius Mailer provides flexible email sending for Sylius apps, with templated messages, configurable transports, and event-driven dispatching. Define email types, recipients, and templates, then trigger emails from your shop or custom code with ease.
Installation
composer require sylius/mailer
Add the service provider to config/app.php:
Sylius\Mailer\MailerServiceProvider::class,
Basic Configuration Publish the config file:
php artisan vendor:publish --provider="Sylius\Mailer\MailerServiceProvider" --tag="config"
Update config/mailer.php with your SMTP/transport settings (e.g., Mailgun, SendGrid, or Laravel's default mail driver).
First Use Case: Sending a Simple Email
Inject the MailerInterface into a service/controller:
use Sylius\Mailer\Sender\MailerInterface;
class UserController
{
public function __construct(private MailerInterface $mailer) {}
public function sendWelcomeEmail()
{
$this->mailer->send(new Email(
'welcome@example.com',
'Welcome!',
'Hello, welcome to our platform!'
));
}
}
Key Classes to Explore
Sylius\Mailer\Sender\MailerInterface: Core interface for sending emails.Sylius\Mailer\Email: Represents an email with to, subject, html, and text properties.Sylius\Mailer\Sender\SwiftMailer: Default implementation using SwiftMailer.Use the Email class's attach() method:
$email = new Email('user@example.com', 'Invoice', 'See attached.');
$email->attach(new \Swift_Attachments_FileAttachment('/path/to/file.pdf'));
$this->mailer->send($email);
Wrap the mailer in a queue job:
use Sylius\Mailer\Sender\MailerInterface;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
class SendEmailJob implements Queueable, SerializesModels
{
use Dispatchable, Queueable, SerializesModels;
public function __construct(
private MailerInterface $mailer,
private Email $email
) {}
public function handle()
{
$this->mailer->send($this->email);
}
}
Dispatch it from a controller:
SendEmailJob::dispatch($this->mailer, $email);
Combine with Laravel's Blade or a templating engine:
$html = view('emails.welcome', ['user' => $user])->render();
$email = new Email('user@example.com', 'Welcome', $html, 'Plain text version');
$this->mailer->send($email);
Iterate and send emails in batches (avoid memory issues):
foreach ($users as $user) {
$email = new Email($user->email, 'Update', 'Your update here.');
$this->mailer->send($email);
}
Use Laravel's Mail facade alongside Sylius' mailer for hybrid workflows:
use Illuminate\Support\Facades\Mail;
use Sylius\Mailer\Email;
// Sylius-style
$this->mailer->send(new Email('to@example.com', 'Subject', 'Body'));
// Laravel-style
Mail::to('to@example.com')->send(new \App\Mail\WelcomeMail());
Mock MailerInterface in PHPUnit:
$mockMailer = $this->createMock(MailerInterface::class);
$mockMailer->expects($this->once())
->method('send')
->with($this->isInstanceOf(Email::class));
$this->app->instance(MailerInterface::class, $mockMailer);
Extend the mailer to log failures:
use Sylius\Mailer\Sender\SwiftMailer;
class LoggingMailer extends SwiftMailer
{
public function send(Email $email)
{
try {
parent::send($email);
} catch (\Exception $e) {
\Log::error('Failed to send email', [
'to' => $email->getTo(),
'subject' => $email->getSubject(),
'error' => $e->getMessage()
]);
throw $e;
}
}
}
Bind it in config/app.php:
'Sylius\Mailer\Sender\MailerInterface' => \App\Services\LoggingMailer::class,
SwiftMailer Dependency
'transport' => [
'dsn' => env('MAIL_MAILER').'://'.env('MAIL_HOST').':'.env('MAIL_PORT'),
],
Email Validation
Email class does not validate email addresses by default. Validate inputs upstream:
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new \InvalidArgumentException('Invalid email address.');
}
Memory Leaks in Bulk Sending
$users->chunk(100)->each(function ($chunk) {
foreach ($chunk as $user) {
$this->mailer->send(new Email($user->email, 'Subject', 'Body'));
}
});
HTML Email Rendering Issues
$email = new Email('user@example.com', 'Subject', $html);
$email->getSwiftMessage()
->getHeaders()
->get('Content-Type')
->setValue('text/html; charset=utf-8');
Check SwiftMailer Transport
config/mailer.php:
'logging' => true,
storage/logs/laravel.log.Verify Email Structure
SwiftMessage object before sending:
$email = new Email('to@example.com', 'Subject', 'Body');
dump($email->getSwiftMessage()->toString());
Common Exceptions
Swift_TransportException: Transport (SMTP) issues. Check credentials/connection.Swift_RfcComplianceException: Invalid email format or headers.Custom Email Classes
Extend Email for domain-specific logic:
class OrderConfirmationEmail extends Email
{
public function __construct(string $to, Order $order)
{
$subject = "Order #{$order->number} Confirmed";
$html = view('emails.order_confirmation', ['order' => $order])->render();
parent::__construct($to, $subject, $html);
}
}
Transport Plugins Add custom transports (e.g., Slack notifications):
use Sylius\Mailer\Sender\Transport\TransportInterface;
class SlackTransport implements TransportInterface
{
public function send(\Swift_Mime_SimpleMessage $message)
{
// Custom Slack logic
}
}
Bind it in config/mailer.php:
'transports' => [
'slack' => [
'class' => \App\Mailer\Transport\SlackTransport::class,
],
],
Event Listeners Trigger events before/after sending:
use Sylius\Mailer\Sender\Events\EmailSent;
use Sylius\Mailer\Sender\Events\EmailSending;
// In a service provider
$this->app->booted(function () {
event(new EmailSending($email));
$this->mailer->send($email);
event(new EmailSent($email));
});
Retry Mechanism Implement exponential backoff for failed sends:
use Sylius\Mailer\Sender\MailerInterface;
class RetryMailer implements MailerInterface
{
public function send(Email $email, int $retries = 3, float $delay = 1)
{
try {
$this->mailer->send($email);
} catch (\Exception $e) {
if ($ret
How can I help you explore Laravel packages today?