Installation
composer require allprogrammic/sendinblue-bundle
For Symfony 4/5, add to config/bundles.php:
return [
// ...
AllProgrammic\Bundle\SendinBlueBundle\AllProgrammicSendinBlueBundle::class => ['all' => true],
];
Configuration
Add your SendinBlue API key to config/packages/sendinblue.yaml:
sendinblue:
api:
key: '%env(SENDINBLUE_API_KEY)%'
Set the env variable in .env:
SENDINBLUE_API_KEY=your_api_key_here
First Use Case Inject the client into a service/controller:
use AllProgrammic\Bundle\SendinBlueBundle\Api\TransactionalMessage;
use AllProgrammic\Bundle\SendinBlueBundle\SendinBlueApiClientInterface;
public function __construct(private SendinBlueApiClientInterface $sendinBlueClient) {}
public function sendWelcomeEmail(string $email)
{
$message = new TransactionalMessage('Welcome!');
$message
->from('noreply@example.com', 'My App')
->addTo($email)
->html($this->twig->render('emails/welcome.html.twig'))
->text($this->twig->render('emails/welcome.txt.twig'));
$this->sendinBlueClient->sendTransactional($message);
}
Transactional Emails
TransactionalMessage for one-off emails (e.g., password resets, notifications).$message
->setTemplateId(123) // Optional: Use SendinBlue templates
->addCc('cc@example.com')
->addAttachment('/path/to/file.pdf', 'filename.pdf');
Batch Processing
foreach ($users as $user) {
$message = (new TransactionalMessage('Monthly Report'))
->from('reports@example.com', 'Reports Team')
->addTo($user->email)
->html($this->renderReport($user));
$this->sendinBlueClient->sendTransactional($message);
}
Template Management
$templates = $this->sendinBlueClient->getTemplates();
$template = $templates->find(fn($t) => $t->name === 'Welcome Email');
Error Handling
try {
$this->sendinBlueClient->sendTransactional($message);
} catch (\AllProgrammic\Bundle\SendinBlueBundle\Exception\SendinBlueException $e) {
$this->logger->error('SendinBlue error: ' . $e->getMessage());
// Retry logic or fallback (e.g., queue the email)
}
symfony/mailer for hybrid setups:
if ($useSendinBlue) {
$this->sendinBlueClient->sendTransactional($message);
} else {
$this->mailer->send($email);
}
// src/EventListener/UserRegisteredListener.php
public function onUserRegistered(UserRegisteredEvent $event)
{
$message = new TransactionalMessage('Account Created');
$message->addTo($event->getUser()->email);
$this->sendinBlueClient->sendTransactional($message);
}
$this->messageBus->dispatch(new SendEmailMessage($message));
API Key Exposure
%env() or .env.Rate Limits
$stats = $this->sendinBlueClient->getAccount()->getStats();
$attempt = 0;
while ($attempt < 3) {
try {
$this->sendinBlueClient->sendTransactional($message);
break;
} catch (RateLimitException $e) {
sleep(2 ** $attempt); // Exponential delay
$attempt++;
}
}
Template IDs
$template = $this->sendinBlueClient->getTemplates()->find(fn($t) => $t->name === 'Welcome');
if (!$template) {
throw new \RuntimeException('Template not found!');
}
HTML/Text Mismatch
// ❌ Missing text part
$message->html('...');
// ✅ Correct
$message->html('...')->text(strip_tags('...'));
Enable Guzzle Debugging:
Add to config/packages/dev/sendinblue.yaml:
sendinblue:
api:
debug: true
Logs will appear in var/log/dev.log.
Validate API Responses: Inspect raw responses for errors:
$response = $this->sendinBlueClient->sendTransactional($message);
if ($response->getStatusCode() !== 200) {
$body = json_decode($response->getBody(), true);
throw new \RuntimeException($body['message'] ?? 'Unknown error');
}
Custom Response Handling Extend the client to add logic:
class CustomSendinBlueClient extends AbstractSendinBlueClient
{
public function sendTransactional(TransactionalMessage $message)
{
$response = parent::sendTransactional($message);
if ($response->getStatusCode() === 200) {
$this->trackEmailSent($message);
}
return $response;
}
}
Register as a service in config/services.yaml:
services:
App\Service\CustomSendinBlueClient:
decorates: 'sendinblue.api.client'
arguments: ['@sendinblue.api.client']
Add Custom Endpoints Use the underlying Guzzle client:
$client = $this->get('sendinblue.api.client')->getClient();
$response = $client->get('smtp/email', [
'query' => ['limit' => 10]
]);
Mock for Testing Replace the client in tests:
// tests/Service/SendinBlueTest.php
public function testSendEmail()
{
$mockClient = $this->createMock(SendinBlueApiClientInterface::class);
$mockClient->expects($this->once())
->method('sendTransactional')
->with($this->isInstanceOf(TransactionalMessage::class));
$this->container->set('sendinblue.api.client', $mockClient);
// Test your service...
}
Webhook Validation Verify SendinBlue webhook signatures:
use AllProgrammic\Bundle\SendinBlueBundle\Webhook\WebhookValidator;
public function handleWebhook(Request $request)
{
$validator = new WebhookValidator($this->getParameter('sendinblue.api.key'));
if (!$validator->validate($request->getContent(), $request->headers->get('X-Signature'))) {
throw new \RuntimeException('Invalid webhook signature');
}
// Process webhook...
}
How can I help you explore Laravel packages today?