Install the Bundle
composer require badpixxel/brevo-bridge
Enable the bundle in config/bundles.php:
return [
// ...
BadPixxel\BrevoBridge\BrevoBridgeBundle::class => ['all' => true],
];
Configure Sendinblue API Key
Add your Sendinblue API key to config/packages/brevo_bridge.yaml:
brevo_bridge:
api_key: '%env(BREVO_API_KEY)%'
default_from: 'noreply@example.com'
Define a Static Email Class
Create a static class (e.g., src/Email/WelcomeEmail.php) extending BadPixxel\BrevoBridge\Email\AbstractEmail:
namespace App\Email;
use BadPixxel\BrevoBridge\Email\AbstractEmail;
class WelcomeEmail extends AbstractEmail
{
protected static $name = 'Welcome Email';
protected static $subject = 'Welcome to Our Platform!';
protected static $templateId = 123; // Your Sendinblue template ID
protected static $to = 'user@example.com';
protected static $variables = [
'username' => 'John Doe',
];
}
Send the Email
Inject the BrevoBridgeService and dispatch:
use BadPixxel\BrevoBridge\Service\BrevoBridgeService;
class SomeController
{
public function __construct(private BrevoBridgeService $brevoService) {}
public function sendWelcomeEmail()
{
$this->brevoService->send(WelcomeEmail::class);
}
}
Email Definition
PasswordResetEmail, InvoiceEmail).protected static $variables = [
'user' => fn() => ['name' => $user->name, 'id' => $user->id],
];
Integration with Symfony Events
Trigger emails via events (e.g., UserRegisteredEvent):
// In an event subscriber
$this->brevoService->send(WelcomeEmail::class, ['user' => $user]);
Admin Panel Integration
SonataAdmin configuration:
# config/packages/sonata_admin.yaml
sonata_admin:
options:
models:
BadPixxel\BrevoBridge\Entity\EmailLog: ~
Batch Processing
$this->brevoService->queue(WelcomeEmail::class, ['user' => $user]);
Dynamic Recipients
Override getTo() in your email class to fetch recipients dynamically:
protected function getTo(): array
{
return $this->userRepository->findAllActiveUsers();
}
Template Management
$this->brevoService->getTemplateManager()->fetchTemplate($templateId);
Logging and Analytics
EmailLog entity to add custom fields (e.g., campaign_id):
// In a migration
$table->integer('campaign_id')->nullable();
Testing
BrevoBridgeService in tests:
$this->brevoService->shouldReceive('send')->once();
API Key Security
BREVO_API_KEY in config. Use environment variables or Symfony’s ParameterBag.Template IDs
static::$templateId) can break if Sendinblue templates are renamed/deleted.brevo_bridge:
templates:
welcome: 123
Sonata Admin Dependencies
sonata-project/user-bundle is installed. If not, disable the admin integration in config/packages/brevo_bridge.yaml:
brevo_bridge:
admin:
enabled: false
Rate Limits
429 Too Many Requests gracefully:
try {
$this->brevoService->send(EmailClass::class);
} catch (RateLimitExceededException $e) {
$this->retryLater();
}
Database Schema
email_log table is auto-created by Doctrine migrations. Customize the schema if needed:
// src/Migrations/VersionYYYYMMDDHHMM.php
$table->addColumn('status', 'string', ['length' => 20]);
Enable API Logging
Configure getbrevo/brevo-php to log requests:
brevo_bridge:
debug: true
Check EmailLog Entries
Query the email_log table for failed sends:
SELECT * FROM email_log WHERE status = 'failed' ORDER BY created_at DESC;
Validate Variables
Ensure static::$variables are serializable. Non-serializable objects (e.g., closures with non-serializable context) will fail:
// Bad: Closure with $this
protected static $variables = ['data' => fn() => $this->fetchData()];
// Good: Static or serializable data
protected static $variables = ['data' => $serializedData];
Test with Sandbox Mode Use Sendinblue’s sandbox API for testing:
brevo_bridge:
sandbox: true
Custom Email Classes
Extend AbstractEmail to add validation or pre-send logic:
class CustomEmail extends AbstractEmail
{
public function validate(): bool
{
if (empty($this->getTo())) {
throw new \RuntimeException('Recipient not set!');
}
return true;
}
}
Event Listeners Dispatch custom events before/after sending:
// In services.yaml
BadPixxel\BrevoBridge\Event\EmailEvents::EMAIL_SENT:
listeners:
- [onEmailSent, App\EventListener\EmailListener]
Transport Layer Replace the default Sendinblue client by overriding the service:
# config/services.yaml
BadPixxel\BrevoBridge\Service\BrevoBridgeService:
arguments:
$client: '@custom_brevo_client'
Twig Integration Use Twig templates for dynamic content:
protected static $templateId = null; // Disable Sendinblue template
protected static $htmlTemplate = '@emails/welcome.html.twig';
How can I help you explore Laravel packages today?