# Laravel Notifications: Email and SMS

> How I use Laravel Notification classes to send the same notification logic across multiple channels — email, SMS, and more.

- Published: 2018-05-06
- Category: Web Development
- Tags: Laravel
- Reading time: 4 min read
- Source: https://www.muhammetsafak.com.tr/en/blog/laravel-notifications-email-and-sms/
- Language: en-US
- Author: Muhammet Şafak

---
As an application grows, so does its notification complexity: order confirmations should go by email, shipping updates by SMS, comment alerts as in-app notifications. Laravel's **notification** system lets you manage [all these different channels](/en/blog/sending-emails-in-laravel-with-mailables-and-templates) through a single class. Adding a new channel doesn't require touching the existing notification logic — that's the real value here.

## How the notification system works

In Laravel, every notification is a class. That class defines which channels it should be sent through and what the message looks like on each channel. You can scaffold one with Artisan:

```bash
php artisan make:notification OrderShipped
```

The generated class lives at `app/Notifications/OrderShipped.php`. It contains two key methods: `via` and `toMail` (or channel-specific methods like `toNexmo`, `toBroadcast`, etc.).

## Email notification

The `via` method returns which channels to use. The `toMail` method builds the mail message:

```php
<?php

namespace App\Notifications;

use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\MailMessage;

class OrderShipped extends Notification
{
    protected $order;

    public function __construct($order)
    {
        $this->order = $order;
    }

    public function via($notifiable)
    {
        return ['mail'];
    }

    public function toMail($notifiable)
    {
        return (new MailMessage)
            ->subject('Your order has been shipped')
            ->line('Your order has been shipped with tracking number ' . $this->order->tracking_number . '.')
            ->action('Track Order', url('/orders/' . $this->order->id))
            ->line('Thank you for your purchase.');
    }
}
```

Sending the notification to a user is as simple as calling `notify`:

```php
<?php

$user->notify(new OrderShipped($order));
```

The `notify` method is available on any model that uses the `Notifiable` trait. The `User` model includes it by default.

## Adding an SMS channel

When you want to send the same notification via SMS, all you need is to add the SMS channel to `via`. Laravel ships with Nexmo (now Vonage) integration out of the box:

```php
<?php

public function via($notifiable)
{
    return ['mail', 'nexmo'];
}

public function toNexmo($notifiable)
{
    return (new NexmoMessage)
        ->content('Your order ' . $this->order->tracking_number . ' has been shipped.');
}
```

I added the SMS channel without touching `toMail`. The notification logic lives in one place; each channel has its own method — that separation holds up well.

## Letting the user decide the channel

In real projects, not every user wants every channel. One person might opt out of SMS; another might prefer email only. The `via` method receives the `$notifiable` object as a parameter, so you can make the decision based on user preferences:

```php
<?php

public function via($notifiable)
{
    $channels = ['mail'];

    if ($notifiable->sms_notifications_enabled) {
        $channels[] = 'nexmo';
    }

    return $channels;
}
```

The notification class itself never changes — a single column in the users table drives the channel list.

## Database notifications

If you want to show a notification inbox inside your application, the `database` channel handles that. Notifications are stored in the `notifications` table, making it straightforward to query unread counts and lists.

```php
<?php

public function via($notifiable)
{
    return ['mail', 'database'];
}

public function toArray($notifiable)
{
    return [
        'order_id'        => $this->order->id,
        'tracking_number' => $this->order->tracking_number,
    ];
}
```

```php
<?php

// Fetch unread notifications
$user->unreadNotifications;

// Mark all as read
$user->unreadNotifications->markAsRead();
```

When I first used the `database` channel, I missed one thing: you need to run a migration to create the `notifications` table. Laravel generates it via `php artisan notifications:table`. I spent a while wondering why notifications were silently disappearing — the table simply didn't exist.

## Async dispatch with queues

Email and SMS delivery take time. Rather than making the user wait for a response after placing an order, you can push notifications onto a queue. Just implement the `ShouldQueue` interface on your notification class:

```php
<?php

use Illuminate\Contracts\Queue\ShouldQueue;

class OrderShipped extends Notification implements ShouldQueue
{
    // ...
}
```

Queue infrastructure is a topic on its own — I'm not going to dive into it here — but adding `ShouldQueue` is the first practical step you can apply immediately in a real project.

## Conclusion

Laravel's notification system has a clean design precisely because it centralizes the "which channel" decision in a single class. Adding a new channel doesn't alter existing logic; it's just a new method. As a project grows and notification types multiply, the value of that separation compounds. In the old approach I used to write separate code per channel, and any change meant updating each one individually. Now the notification logic lives in one place.

One more thing to watch as notification classes get larger: the `via` method might end up making channel decisions not just based on user preferences, but also on conditions tied to the notification itself — for instance, send SMS only when the order amount exceeds a threshold, otherwise just send email. If that logic piles up inside `via`, the class starts to bloat. In those cases it's cleaner to create separate notification classes and push the "which notification to send" decision up into the calling business logic. A notification class should know *how* to send; *when and under what conditions* is the concern of whoever calls it.
