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: Since Laravel doesn’t natively use Symfony’s Messenger, install the standalone Twilio SDK for direct Laravel integration:
composer require twilio/sdk
Configure Environment Variables:
Add to .env:
TWILIO_SID=your_account_sid
TWILIO_TOKEN=your_auth_token
TWILIO_FROM=+1234567890 # Your Twilio number
First Use Case: Send an SMS Create a service to wrap Twilio’s client (Laravel-style):
// app/Services/TwilioNotifier.php
namespace App\Services;
use Twilio\Rest\Client;
class TwilioNotifier
{
protected Client $client;
public function __construct()
{
$this->client = new Client(
config('services.twilio.sid'),
config('services.twilio.token')
);
}
public function sendSms(string $to, string $body): void
{
$this->client->messages->create(
$to,
[
'from' => config('services.twilio.from'),
'body' => $body,
]
);
}
}
Register the Service:
Bind it in AppServiceProvider:
public function register()
{
$this->app->singleton(TwilioNotifier::class);
}
Usage in Controllers/Jobs:
use App\Services\TwilioNotifier;
public function sendWelcomeSms()
{
$notifier = app(TwilioNotifier::class);
$notifier->sendSms('+15551234567', 'Welcome to our app!');
}
For Symfony-like workflows (e.g., Messenger integration), see Implementation Patterns.
If your Laravel app uses Laravel Echo/Events + Queues, adapt the Symfony Transport pattern:
// app/Notifications/TwilioTransport.php
namespace App\Notifications;
use Symfony\Component\Notifier\Transport\TransportInterface;
use Symfony\Component\Notifier\Message\SmsMessage;
use Twilio\Rest\Client;
class TwilioTransport implements TransportInterface
{
protected Client $client;
public function __construct()
{
$this->client = new Client(
config('services.twilio.sid'),
config('services.twilio.token')
);
}
public function send(SmsMessage $message): void
{
$this->client->messages->create(
$message->getRecipients()[0],
[
'from' => config('services.twilio.from'),
'body' => $message->getSubject(),
]
);
}
public function supports(string $transportName): bool
{
return 'twilio' === $transportName;
}
}
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->singleton('notifier.transport.twilio', function () {
return new TwilioTransport();
});
}
use Illuminate\Notifications\Notification;
use Symfony\Component\Notifier\Message\SmsMessage;
class WelcomeSms extends Notification
{
public function via($notifiable)
{
return ['twilio'];
}
public function toTwilio($notifiable)
{
return (new SmsMessage($notifiable->phone))
->subject('Welcome!');
}
}
Leverage Laravel’s Route::post + middleware for secure webhook validation:
// routes/web.php
Route::post('/twilio/webhook', [TwilioWebhookController::class]);
// app/Http/Controllers/TwilioWebhookController.php
use Symfony\Component\Notifier\Bridge\Twilio\Validator\WebhookValidator;
class TwilioWebhookController extends Controller
{
public function __invoke(Request $request)
{
$validator = new WebhookValidator(
config('services.twilio.token'),
$request->header('X-Twilio-Signature')
);
if (!$validator->isValid($request->getContent())) {
abort(403, 'Invalid webhook signature');
}
// Process event (e.g., message status)
$event = json_decode($request->getContent(), true);
// ...
}
}
Use Laravel’s Notification facade for batch sends:
use Illuminate\Notifications\Notification;
Notification::send(
User::where('is_active', true)->get(),
new WelcomeSms()
);
Combine Twilio with email fallbacks:
// In Notification class
public function via($notifiable)
{
return ['twilio', 'mail'];
}
Twilio\Rest\Client:
$client = Mockery::mock(Client::class);
$client->shouldReceive('messages->create')->once();
$this->app->instance(Client::class, $client);
HttpTestResponse for webhook validation:
$response = $this->post('/twilio/webhook', [], [
'HTTP_X_TWILIO_SIGNATURE' => 'valid_hmac',
]);
$response->assertOk();
Symfony Abstraction Leakage:
Message and Transport interfaces. In Laravel, avoid direct dependency injection of Symfony classes. Use adapters (e.g., TwilioTransport above).Webhook Security:
Request object requires explicit header access:
$signature = $request->header('X-Twilio-Signature'); // Not $request->input()
Number Formatting:
+15551234567). Laravel’s Str::of() or libphonenumber can help validate:
use libphonenumber\PhoneNumberUtil;
$util = PhoneNumberUtil::getInstance();
$phone = $util->parse($phoneNumber, 'US');
$e164 = $util->format($phone, PhoneNumberFormat::E164);
Rate Limiting:
try {
$notifier->sendSms($to, $body);
} catch (Exception $e) {
if ($e->getCode() === 20001) { // "Too Many Requests"
sleep(2);
retry();
}
}
Cost Overruns:
// Log all outgoing messages
$this->client->messages->create(/* ... */)->log();
Enable Twilio Debugging:
Add to .env:
TWILIO_DEBUG=true
Note: This requires patching the SDK or using a wrapper.
Log Raw Responses:
Extend TwilioTransport to log Twilio’s API responses:
public function send(SmsMessage $message): void
{
$response = $this->client->messages->create(/* ... */);
\Log::debug('Twilio Response:', [
'sid' => $response->sid,
'status' => $response->status,
]);
}
Test with Sandbox Numbers:
Use Twilio’s sandbox numbers (e.g., +15017122661) to avoid costs during development.
Check Twilio’s Status Page: https://www.twilio.com/status for outages.
TwilioMessageBuilder to support:How can I help you explore Laravel packages today?