Laravel cookbook · Beginner
Send queued notifications over several channels
Emails slow down requests and users want some messages by Slack or SMS instead.
Approach
Create a notification that implements ShouldQueue, choose channels per user in via(), and build each
channel's message in its own method.
Solution
<?php
// app/Notifications/InvoicePaid.php
namespace App\Notifications;
use App\Models\Invoice;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class InvoicePaid extends Notification implements ShouldQueue
{
use Queueable;
public function __construct(public Invoice $invoice)
{
$this->afterCommit();
}
public function via(object $notifiable): array
{
return $notifiable->prefers_sms ? ['vonage', 'database'] : ['mail', 'database'];
}
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject("Invoice {$this->invoice->number} paid")
->greeting("Hi {$notifiable->name},")
->line('Thanks, we received your payment of '.$this->invoice->formattedTotal().'.')
->action('View invoice', route('invoices.show', $this->invoice));
}
public function toArray(object $notifiable): array
{
return ['invoice_id' => $this->invoice->id, 'total' => $this->invoice->total_cents];
}
}
<?php
$invoice->customer->notify(new \App\Notifications\InvoicePaid($invoice));
Pitfalls
- Sending mail synchronously in requests; one slow SMTP server makes the app slow.
- Not calling
afterCommit()when notifying inside transactions. - Including sensitive data in notification payloads stored in the database channel.
Variations
- Preview mail templates in the browser by returning the
MailMessagefrom a local route. - Use
Notification::fake()andassertSentToin tests.
Further reading: Queueing notifications
Reference: https://laravel.com/docs/13.x/notifications#queueing-notifications
More Laravel recipes
- Authorize actions with policies
- Cache expensive data with stale-while-revalidate
- Call external APIs with timeouts, retries and fakes
- Catch N+1 queries with strict Eloquent mode
- Delete old records automatically with prunable models
- Dispatch events and listeners after the transaction commits
- Issue scoped API tokens with Sanctum
- Make queued jobs reliable with retries, backoff and uniqueness