accord/mandrill-swiftmailer-bundle
Symfony bundle that adds a SwiftMailer transport for sending email via Mandrill’s API. Configure your Mandrill API key (plus optional async mode and subaccount), register the bundle, then set SwiftMailer’s transport to accord_mandrill.
Install the Bundle
composer require accord/mandrill-swiftmailer-bundle
Add to AppKernel.php:
new Accord\MandrillSwiftMailerBundle\AccordMandrillSwiftMailerBundle(),
Configure API Key
Add your Mandrill API key to config/packages/accord_mandrill_swift_mailer.yaml (or config.yml):
accord_mandrill_swift_mailer:
api_key: "%env(MANDRILL_API_KEY)%" # Use env vars for security
async: false
subaccount: ~
Set SwiftMailer Transport
In config/packages/swiftmailer.yaml (or config.yml):
swiftmailer:
transport: accord_mandrill
First Use Case
Send an email via Laravel’s Mail facade (or Symfony’s SwiftMailer):
Mail::send('emails.welcome', [], function ($message) {
$message->to('user@example.com')
->subject('Welcome!');
});
Basic Email Sending
Use Laravel’s Mail facade or Symfony’s SwiftMailer as usual. The bundle replaces the default transport with Mandrill’s API.
Async vs. Sync
async: true in config to queue emails via Mandrill’s async API (reduces latency).async: false) is default; useful for immediate delivery (e.g., password resets).Subaccounts
Use subaccount in config to route emails to a specific Mandrill subaccount (e.g., for multi-tenant apps).
Templates & Variables
Leverage Mandrill’s templating system by passing template_name and template_content to the Swift_Message:
$message->getHeaders()->addTextHeader('X-MC-Template', 'template_name');
$message->getHeaders()->addTextHeader('X-MC-Personalization', json_encode([
'user' => ['name' => 'John']
]));
Attachments & Inline Images Use SwiftMailer’s built-in methods:
$message->attach(spl_file_get_contents('/path/to/file.pdf'));
$message->embed(Swift_Image::fromPath('/path/to/image.jpg'));
Event Listeners Hook into Mandrill’s webhooks (e.g., for tracking opens/clicks) by configuring Mandrill’s webhook URL to point to your Laravel endpoint.
Mailable and use SwiftMailer methods directly:
public function build()
{
$this->markdown('emails.welcome')
->withSwiftMessage(function ($message) {
$message->getHeaders()->addTextHeader('X-MC-Template', 'welcome_template');
});
}
Mail::fake() to mock Mandrill calls in tests.config/packages/swiftmailer.yaml for debugging:
swiftmailer:
logging: true
API Key Exposure
config.yml. Use environment variables (%env(MANDRILL_API_KEY)%) or Laravel’s .env..env is in your .gitignore.Async Mode Quirks
async: true) are sent to Mandrill’s queue but may not be delivered immediately. Use sync mode for critical emails (e.g., OTPs).Rate Limits
try {
Mail::send(...);
} catch (\Exception $e) {
if (strpos($e->getMessage(), 'rate limit') !== false) {
sleep(10); // Backoff
retry();
}
}
Subaccount Misconfiguration
subaccount is set but invalid, emails may fail silently. Validate the subaccount exists in Mandrill’s dashboard.SwiftMailer Deprecations
SwiftMailer (v5.x). Ensure your Laravel version (v5.8+) is compatible. Avoid mixing with newer symfony/mailer.Enable Verbose Logging
Add to config/packages/swiftmailer.yaml:
swiftmailer:
logging: true
spool: { type: 'memory' } # Logs all emails in memory (for debugging)
Check logs in storage/logs/laravel.log for Mandrill API responses.
Mandrill API Errors
$response = Http::get('https://mandrillapp.com/api/1.0/messages/status.json', [
'key' => config('accord_mandrill_swift_mailer.api_key'),
]);
400 Bad Request: Invalid email format or missing headers.403 Forbidden: Invalid API key or subaccount.429 Too Many Requests: Hit rate limits.Testing Locally
swiftmailer:
transport: smtp
host: mailhog
port: 1025
Custom Transport Extend the bundle’s transport to add features (e.g., custom headers, retry logic):
use Accord\MandrillSwiftMailerBundle\Transport\MandrillTransport;
class CustomMandrillTransport extends MandrillTransport
{
public function isStarted()
{
// Add custom logic (e.g., check Mandrill uptime)
return parent::isStarted() && $this->checkMandrillStatus();
}
}
Override the service in config/services.yaml:
services:
Accord\MandrillSwiftMailerBundle\Transport\MandrillTransport: '@App\CustomMandrillTransport'
Event Subscribers Listen to Mandrill’s webhooks (e.g., for tracking) by creating a Symfony event subscriber:
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
class MandrillWebhookSubscriber
{
public function onKernelRequest(GetResponseEvent $event)
{
if ($event->isMasterRequest() && $event->getRequest()->getPathInfo() === '/mandrill/webhook') {
$data = json_decode($event->getRequest()->getContent(), true);
// Process webhook (e.g., log opens/clicks)
}
}
}
Register the subscriber in config/services.yaml:
services:
App\EventSubscriber\MandrillWebhookSubscriber:
tags: ['kernel.event_subscriber']
Fallback Transport Implement a fallback to a local SMTP if Mandrill fails:
swiftmailer:
transport: '%env(MAIL_TRANSPORT)%' # Defaults to 'accord_mandrill'
fallback_transport: '%env(MAIL_FALLBACK_TRANSPORT)%' # e.g., 'smtp'
Use a custom transport factory to switch dynamically.
How can I help you explore Laravel packages today?