Laravel Notifications: Stop Reinventing the Messaging Wheel 📬
Laravel Notifications: Stop Reinventing the Messaging Wheel 📬
You know that moment when your boss asks "Can we also send this as a Slack message?" and you realize you've hardcoded email logic everywhere? Yeah, Laravel Notifications are here to save your sanity!
Think of notifications as the Swiss Army knife of messaging. One notification class, multiple delivery channels. Email today, SMS tomorrow, carrier pigeon next week? No problem!
The Old Way: Pain and Suffering 😫
Remember when sending a simple notification meant writing 47 lines of code?
// Sending an order confirmation the hard way
Mail::to($user)->send(new OrderConfirmationEmail($order));
// Now boss wants SMS too... time to duplicate code!
SMS::send($user->phone, "Order #{$order->id} confirmed!");
// And now Slack... great, more copypasta!
Slack::sendMessage($webhook, "New order from {$user->name}");
The problem: Three different APIs, three different implementations, three times the bugs! 🐛🐛🐛
The Laravel Way: One Ring to Rule Them All 💍
Laravel Notifications unify all messaging into one clean API. Here's the magic:
// One line. Multiple channels. Chef's kiss! 👨🍳
$user->notify(new OrderConfirmed($order));
That's it! Behind the scenes, Laravel can send this via email, SMS, Slack, database, broadcast events, and more. You just flip switches!
Building Your First Notification 🏗️
Let's create an order confirmation notification:
php artisan make:notification OrderConfirmed
Laravel generates this beautiful template:
namespace App\Notifications;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\MailMessage;
class OrderConfirmed extends Notification
{
public function __construct(public Order $order)
{
// Accept the data you need
}
// Which channels should this notification use?
public function via($notifiable)
{
return ['mail', 'database', 'slack'];
}
// How to send via email
public function toMail($notifiable)
{
return (new MailMessage)
->subject('Order Confirmed! 🎉')
->greeting("Hey {$notifiable->name}!")
->line("Your order #{$this->order->id} is confirmed.")
->action('View Order', url("/orders/{$this->order->id}"))
->line('Thanks for shopping with us!');
}
// How to store in database
public function toArray($notifiable)
{
return [
'order_id' => $this->order->id,
'amount' => $this->order->total,
];
}
}
Look at that! One class, multiple outputs. Beautiful! ✨
Real Talk: The via() Method Is Your Control Panel 🎛️
The via() method is where the magic happens. You can dynamically choose channels:
public function via($notifiable)
{
// VIP customers get the full treatment
if ($notifiable->is_vip) {
return ['mail', 'sms', 'slack', 'database'];
}
// Regular folks get email and in-app
return ['mail', 'database'];
}
Pro tip: User preferences? Easy!
public function via($notifiable)
{
$channels = ['database']; // Always save to database
if ($notifiable->notification_preferences['email']) {
$channels[] = 'mail';
}
if ($notifiable->notification_preferences['sms']) {
$channels[] = 'nexmo'; // or 'vonage' now
}
return $channels;
}
Now your users can control how they're notified. Fancy! 🎩
Database Notifications: The In-App Bell 🔔
Ever wondered how to build those little notification dropdowns? Laravel's got you covered!
Migration (already included):
php artisan notifications:table
php artisan migrate
In your notification:
public function toArray($notifiable)
{
return [
'title' => 'Order Confirmed',
'message' => "Order #{$this->order->id} is ready!",
'order_id' => $this->order->id,
];
}
Displaying them is stupid simple:
// Get unread notifications
$notifications = auth()->user()->unreadNotifications;
// Mark as read
auth()->user()->unreadNotifications->markAsRead();
// Get all notifications
$all = auth()->user()->notifications;
In your blade:
@foreach(auth()->user()->unreadNotifications as $notification)
<div class="notification">
{{ $notification->data['message'] }}
<span>{{ $notification->created_at->diffForHumans() }}</span>
</div>
@endforeach
Boom! You've got an in-app notification system! 💥
Slack Notifications: Because Your Team Lives There 💬
Want to ping Slack when important stuff happens?
public function toSlack($notifiable)
{
return (new SlackMessage)
->success()
->content('New order received! 🎉')
->attachment(function ($attachment) use ($notifiable) {
$attachment->title("Order #{$this->order->id}")
->fields([
'Customer' => $notifiable->name,
'Amount' => '$' . $this->order->total,
'Items' => $this->order->items->count(),
]);
});
}
Setup: Add a Slack webhook URL to your .env:
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
And configure the route in config/services.php:
'slack' => [
'notifications' => [
'webhook_url' => env('SLACK_WEBHOOK_URL'),
],
],
SMS Notifications: For When Email Isn't Enough 📱
Laravel supports Vonage (formerly Nexmo) out of the box:
public function toVonage($notifiable)
{
return (new VonageMessage)
->content("Your order #{$this->order->id} has shipped! 🚚");
}
Make sure your User model has a phone number:
public function routeNotificationForVonage($notification)
{
return $this->phone_number;
}
Note: You'll need to install the Vonage package and add credentials to your .env. But the code? Super clean! 👌
On-Demand Notifications: When Users Aren't in Your Database 🎯
Need to notify someone who's not a registered user?
use Illuminate\Support\Facades\Notification;
// Send to anyone!
Notification::route('mail', '[email protected]')
->route('vonage', '5555551234')
->notify(new InvoicePaid($invoice));
Translation: "Hey Laravel, send this notification to this email and phone number, I don't care if they're in the database!"
Queue Them Up: Don't Make Users Wait ⏰
Sending notifications can be slow (emails, API calls, etc.). Queue them!
Option 1: Queue specific channels
// In your notification
public function via($notifiable)
{
return ['mail', 'database'];
}
// Mail will be queued automatically if you implement ShouldQueue
Option 2: Make the whole notification queueable
use Illuminate\Contracts\Queue\ShouldQueue;
class OrderConfirmed extends Notification implements ShouldQueue
{
use Queueable;
// That's it! Now all channels are queued
}
One interface, instant performance boost! 🚀
Customizing Email Templates 🎨
Those default Laravel email templates are nice, but what if you want your brand?
php artisan vendor:publish --tag=laravel-mail
Now edit resources/views/vendor/mail/html/themes/default.css to match your colors!
Or build fully custom emails:
public function toMail($notifiable)
{
return (new MailMessage)
->view('emails.order-confirmed', [
'order' => $this->order,
'user' => $notifiable,
]);
}
Bonus Round: Notification Events 🎪
Want to log every notification sent? Use events!
// In EventServiceProvider
protected $listen = [
NotificationSent::class => [
LogNotification::class,
],
];
// In your listener
public function handle(NotificationSent $event)
{
// $event->notification
// $event->notifiable
// $event->channel
// $event->response
Log::info("Sent {$event->notification} via {$event->channel}");
}
Use cases:
- Analytics (how many emails are we sending?)
- Debugging (did that notification actually go out?)
- Rate limiting (prevent spam)
The Notification Checklist ✅
Before you ship notifications:
- Used
via()to control channels dynamically - Implemented
ShouldQueuefor slow channels - Added database notifications for in-app alerts
- Let users control their notification preferences
- Tested each channel (don't spam your real Slack!)
- Customized email templates to match your brand
- Added
routeNotificationFor*()methods where needed
Pro Tips That'll Save Your Butt 💡
1. Rate limiting notifications:
// In your notification
public function middleware()
{
return [
new RateLimited('notifications'),
];
}
2. Conditional channels:
public function via($notifiable)
{
// Don't send marketing emails to unsubscribed users
if ($this->type === 'marketing' && !$notifiable->marketing_emails) {
return ['database'];
}
return ['mail', 'database'];
}
3. Testing notifications:
// In your tests
Notification::fake();
// Do something that triggers notifications
$user->notify(new OrderConfirmed($order));
// Assert it was sent
Notification::assertSentTo($user, OrderConfirmed::class);
Real Talk: Common Mistakes 💬
Mistake #1: "I'll just use Mail::send() everywhere"
- Why it hurts: When you need to add channels, you're screwed
- Fix: Start with notifications from day one
Mistake #2: "I don't need to queue notifications"
- Why it hurts: Users wait 3 seconds for emails to send
- Fix: Add
implements ShouldQueue- takes 5 seconds
Mistake #3: "I'll build my own notification system"
- Why it hurts: You'll reinvent the wheel... poorly
- Fix: Laravel's notification system is battle-tested. Use it!
The Bottom Line 🎯
Laravel Notifications are like having a universal remote for messaging:
- One button (one line of code)
- Multiple devices (email, SMS, Slack, database, etc.)
- Easy to add new devices (just implement a new channel)
- Works even if you're not looking (queueable by default)
Stop writing custom mailers for every feature. Stop duplicating notification logic. Stop making life hard!
Use Laravel Notifications and thank me later when your boss asks: "Can we send this via Discord too?" and you reply: "Sure, give me 5 minutes!" 😎
Want to chat about Laravel? Hit me up on LinkedIn!
Enjoying these posts? Star the blog repo on GitHub and let me know what topics you want next!
Now go forth and notify responsibly! 📬✨