symfony/twilio-notifier
Symfony Notifier bridge for Twilio. Configure via TWILIO_DSN (SID, token, from) to send SMS, and customize messages with TwilioOptions such as webhook URL and other provider-specific settings.
Install the Package (via Composer):
composer require symfony/twilio-notifier
Note: Laravel doesn’t natively use Symfony’s Messenger, so this package will require adaptation.
Configure Twilio DSN in .env:
TWILIO_DSN=twilio://SID:TOKEN@default?from=+1234567890
Replace SID, TOKEN, and from with your Twilio credentials.
Create a Symfony Messenger Transport Adapter (Laravel doesn’t use Messenger natively, so wrap it):
// app/Providers/AppServiceProvider.php
use Symfony\Component\Notifier\Notifier;
use Symfony\Component\Notifier\Transport\TwilioDsn;
public function register()
{
$this->app->singleton('twilio.notifier', function ($app) {
$dsn = new TwilioDsn($_ENV['TWILIO_DSN']);
return new Notifier([$dsn]);
});
}
First Use Case: Send an SMS
use Symfony\Component\Notifier\Message\SmsMessage;
$notifier = app('twilio.notifier');
$message = new SmsMessage('+15551234567', 'Hello from Laravel!');
$notifier->send($message);
Use TwilioOptions for advanced features like media, webhooks, or status callbacks:
use Symfony\Component\Notifier\Bridge\Twilio\TwilioOptions;
$sms = new SmsMessage('+15551234567', 'Your OTP: 123456');
$options = (new TwilioOptions())
->mediaUrl('https://example.com/verification.png')
->statusCallback('https://your-app.com/twilio/callback')
->statusCallbackMethod('POST');
$sms->options($options);
$notifier->send($sms);
Wrap the notifier in a Laravel job for async processing:
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Symfony\Component\Notifier\Message\SmsMessage;
class SendSmsJob implements ShouldQueue
{
use Queueable;
public function handle()
{
$notifier = app('twilio.notifier');
$message = new SmsMessage('+15551234567', 'Queued message!');
$notifier->send($message);
}
}
Leverage Symfony’s webhook validation for security:
// routes/web.php
use Symfony\Component\Notifier\Bridge\Twilio\WebhookValidator;
Route::post('/twilio/webhook', function (Request $request) {
$validator = new WebhookValidator($_ENV['TWILIO_AUTH_TOKEN']);
if ($validator->validate($request->headers->all(), $request->getContent())) {
// Process webhook
}
});
Use Laravel’s collections or Eloquent to batch-send messages:
use Symfony\Component\Notifier\Message\SmsMessage;
$users = User::where('needs_notification', true)->get();
$notifier = app('twilio.notifier');
foreach ($users as $user) {
$notifier->send(new SmsMessage($user->phone, "Hello, {$user->name}!"));
}
Combine Twilio with other channels (e.g., email) for reliability:
use Symfony\Component\Notifier\Message\SmsMessage;
use Symfony\Component\Notifier\Message\Email;
$notifier = app('twilio.notifier');
$notifier->send([
new SmsMessage('+15551234567', 'Primary SMS'),
new Email('user@example.com', 'Fallback Email', 'Backup content'),
]);
Symfony Dependency Overhead
Transport interface for testing.Queue Integration Quirks
ShouldQueue jobs, but Symfony’s Notifier is synchronous by default.Webhook Security
Route::post('/webhook', function () {
$validator = new WebhookValidator($_ENV['TWILIO_AUTH_TOKEN']);
if (!$validator->validate(request()->headers, request()->getContent())) {
abort(403);
}
// Process
})->middleware('throttle:60,1');
Number Validation
use Symfony\Component\Notifier\Bridge\Twilio\Validator\PhoneNumberValidator;
$validator = new PhoneNumberValidator();
if (!$validator->validate('+15551234567')) {
throw new \InvalidArgumentException('Invalid phone number');
}
Rate Limiting
throttle middleware or a queue with batching:
Queue::later(now()->addSeconds(1), new SendSmsJob());
Enable Symfony Notifier Logging
Add to config/logging.php:
'channels' => [
'notifier' => [
'driver' => 'single',
'path' => storage_path('logs/notifier.log'),
'level' => 'debug',
],
],
Then configure the notifier to use this channel.
Inspect Raw Twilio Requests Use a debug transport to log outgoing requests:
$notifier = new Notifier([
new DebugTransport(new TwilioDsn($_ENV['TWILIO_DSN'])),
]);
Test with Twilio Sandbox Use Twilio’s sandbox for development to avoid costs:
TWILIO_DSN=twilio://SID:TOKEN@sandbox?from=+1234567890
Custom Transports
Extend Symfony\Component\Notifier\Transport\TransportInterface to support non-Twilio channels:
class CustomTransport implements TransportInterface
{
public function __invoke(MessageInterface $message, array $failedRecipients = []): void
{
// Custom logic
}
}
Message Transformers Modify message content before sending:
$message = new SmsMessage('+15551234567', 'Default content');
$message->setContent(fn ($content) => strtoupper($content));
Event Listeners
Hook into Symfony’s MessageSentEvent (requires Symfony’s EventDispatcher):
$dispatcher->addListener(MessageSentEvent::class, function (MessageSentEvent $event) {
// Log or analyze sent messages
});
Service Container Binding Avoid circular dependencies by binding the notifier as a singleton:
$this->app->singleton('twilio.notifier', function ($app) {
return new Notifier([new TwilioDsn($_ENV['TWILIO_DSN'])]);
});
Configuration Management Use Laravel’s config system to centralize Twilio settings:
// config/services.php
'twilio' => [
'dsn' => env('TWILIO_DSN'),
'from' => env('TWILIO_FROM'),
],
Then inject via constructor:
public function __construct(public array $config) {}
Testing Mock the notifier in tests:
$notifier = Mockery::mock(Notifier::class);
$notifier->shouldReceive('send')->once();
$this->app->instance('twilio.notifier', $notifier);
How can I help you explore Laravel packages today?