How to use Laravel's notification system (PHP tutorial)

Check new notifications queued in PHP using Laravel's email and SMS notification system.

Laravel can be used to send email notifications. Notifications are informational messages that app users receive. They are mostly used to notify people about specific transactions or events, such as password changes, orders, and so on. Laravel includes a feature called Notification. It enables you to send a message to any user through various communication channels. Today, we'll go over sending email notifications and how to do so in your app.

laravel email notifications

Laravel supports notification channels.

You may require an alternative notification method in addition to email notifications. Aside from mail, these are:

SMS TXT notifications

Users will receive text notifications on their phones. SMS notifications in Laravel are handled by the Vonage API, formerly known as the Nexmo API. You may, however, use another SMS provider such as MailSlurp.

Slack notifications

Users will receive notifications in Slack. You must configure the Incoming Webhooks integration to send data into Slack in real-time for this to work.

UI updates

Users will receive notifications in the app's user interface if the database is updated. Notification information is stored in a database table. It is accessed by your JavaScript client in order to return notifications for a notifiable user.

Real time notifications (websockets)

Notifications are broadcast in real-time to a notifiable user. When some data on the server is updated, a message is sent to the JavaScript client via a WebSocket connection.

Custom channels

If a custom notification channel is required, custom drivers can be written to deliver notifications. We can check new notifications queued using any channel.

How do you make an email notification?

The make: notification Artisan command in Laravel is used to create notifications.

php artisan make:notification StatusUpdate

All notifications are saved in the directory app/Notifications. Once created, your StatusUpdate.php file will contain the following content:

<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;

class StatusUpdate extends Notification
{
    use Queueable;

    public function __construct()
    {
        //
    }

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

    public function toMail($notifiable)
    {
        return (new MailMessage)
                    ->line('First line of notification')
                    ->action('Notification Action', url('/'))
                    ->line('Welcome to our app!');
    }

    public function toArray($notifiable)
    {
        return [
            //
        ];
    }
}

Let us format it as a message to be sent via email. Later we can check new notifications queued.

Formatting of notifications

You must return it directly from a route to preview all variations of the email. You don't have to send it to a real or a fake user. To accomplish this, we must add the following line to web.php in the routes/ directory:

Route::get('send', 'NotifyController@index);

And here's how to see a preview of your notification:

Route::get('mail', function () {
    $sale = App\Order::find(1);

    return (new App\Notifications\StatusUpdate($sale))
                ->toMail($sale->user);
});

Each notification in Laravel is represented by a single class. If you want your app to send email notifications, you have two options: via and toMail.

Laravel Via method

The via method takes a $notifiable entity as input and defines the notification delivery channel. The required parameter, return ['mail'], is already present by default in the code above.

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

toMail method

toMail is a message-building method that is called via the method. It should return an Illuminate\Notifications\Messages\MailMessage instance after receiving a $notifiable entity. You can configure email parameters with toMail. As an example, your email message could include a text line (line), a call-to-action button (action), a greeting line (greeting), and so on. Consider the following example:

public function toMail($notifiable)
{
  return (new MailMessage)
  ->greeting('Hello!')
  ->line('Welcome to my site')
  ->action('Check out the deals', url('/'))
  ->line('See you next time!');
}

We defined several methods provided by the MailMessage object in this section. The notification will be converted into an HTML and plain-text responsive email template.

If you want to notify users of a failed activity or error, use the error method. It will highlight the CTA button in your email in red. Here's what it looks like under the hood:

public function toMail($notifiable)
{
  return (new MailMessage)
  ->error()
  ->subject('Payment issues')
  ->line('Your payment failed.')
  ->action('Try again', url('/'));
}

You can use the view method to render the notification message if you prefer to use a custom template. Instead of defining the "lines" of text, it will specify a template to be used.

public function toMail($notifiable)
{
  return (new MailMessage)->view(
  'emails.order', ['order' => $this->order]
  );
}

For example, remember to place your template in resources/views/emails/order.blade.php.

Another option is to create a mailable class and return it from toMail as shown below: use App\Mail\StatusUpdate as Mailable;

public function toMail($notifiable)
{
  return (new Mailable($this->order))->to($this->user->email);
}

Changing the email notification characteristics

There are several options we can configure when using new notifications.

Sender

The address from which the email notification is sent is set by default in the configuration file config/mail.php. It is not necessary to modify this file if you want to use a specific address. You can use the from method to specify it as follows:

public function toMail($notifiable)
{
  return (new MailMessage)
  ->from('sender@myserver.com', 'Sender')
}

Recipient

The Laravel Notification system emails the recipient who has been identified as a user of your app. However, you can change the email address of the recipient. You must define a routeNotificationForMail method on the notifiable entity to accomplish this. As an example:

<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
  use Notifiable;
  public function routeNotificationForMail($notification)
  {
}   // Return email address only
    return $this->email_address;
  }
}   // Return both name and email address
        return [$this->email_address => $this->name];
    }
}

Subject

By default, the email subject is formed by the notification's class name. However, it is automatically formatted in "title case." In our example, the class was called StatusUpdate. As a result, the subject of the email will be Status Update. You can use the subject method to specify a specific subject for your notification:

public function toMail($notifiable)
{
  return (new MailMessage)
  ->subject('Spring sale')
}

Finally, here is the email notification we received:

<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class StatusUpdate extends Notification
{
  use Queueable;
  public function __construct()
  {
    //
  }
  public function via($notifiable)
  {
    return ['mail'];
  }
  public function toMail($notifiable)
  {
    return (new MailMessage)
    ->subject('Spring sale')
    ->from('sender@myserver.com', 'Sender')
    ->greeting('Howdy!')
    ->line('New sales items are available')
    ->action('See it now', url('/'))
    ->line('Cya!');
  }
  public function toArray($notifiable)
  {
    return [
      //
    ];
  }
}

Let's get the notification out there as soon as it's ready!

How do I send out email notifications?

Now we want to check new notifications queued and send our emails.

Setting up the email sender

First, we must create a configuration that will be used to send emails. Laravel makes use of the well-known SwiftMailer library. It supports a variety of popular email services, including MailSlurp, Mailgun, Amazon SES, and others. The Laravel documentation contains the configuration for the API-based drivers.

If you prefer to use a specific SMTP relay service for email sending, you must modify the configuration in the root directory's .env file. Here are the settings for the MailSlurp SMTP server, for example:

APP_NAME="YOUR_APP_NAME"
MAIL_MAILER=smtp
MAIL_HOST=mx.mailslurp.com
MAIL_PORT=2525
MAIL_USERNAME=<username>
MAIL_PASSWORD=<password>
MAIL_ENCRYPTION=null
MAIL_FROM_NAME=<Sender name>
MAIL_FROM_ADDRESS=<Sender email address>

How notifications are sent

In Laravel, there are two methods for sending email notifications: Notifiable trait and Notification facade. Sending with the Notifiable property. The Notifiable trait includes the notify method for sending notifications. The trait is implemented by the App\User class, which becomes the notifiable entity.

<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
  use Notifiable;
}
notify anticipates receiving a notification instance:
use App\Notifications\StatusUpdate;
$user->notify(new StatusUpdate($sale));

If you use the Notifiable trait for notification sending, NotifyController.php will look like this:

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
use Notification;
use App\Notifications\StatusUpdate;
use Illuminate\Notifications\Notifiable;
class NotifyController extends Controller
{
  public function __construct()
  {
    $this->middleware('auth');
  }
  public function index()
  {
    $user->notify(new StatusUpdate($sale));
  }
}

You can use the Notifiable trait on any of your classes, not just the App\User class.

Sending with Notification facade

Facades in Laravel are similar to static methods in classes, but with a more expressive syntax and improved testability and flexibility. They allow you to use Laravel's features without having to remember long class names that must be manually configured. The Notification facade can send notifications to multiple notifiable entities. To use it, pass the notifiable entities and notification instance to the send method in the following order:

Notification::send($users, new StatusUpdate($sale));

On-demand and queued notifications

Notifications will be sent to app users in the examples above. What if you need to alert someone else? In this case, the Notification::route method can be used to send the notification to the recipient you specify. Here is how it looks:

Notification::route('mail', 'bad-user@example.com')->notify(new StatusUpdate($sale));

You might be interested in queued emails. It's not about SMTP queues, but about queued notifications, which will allow you to improve the response time of your app. You must add the ShouldQueue interface and the Queueable trait to your class to accomplish this. You do not need to import them because they are already present for all notifications generated by make

. All you have to do is include them in your class:

<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
class StatusUpdate extends Notification implements ShouldQueue
{
  use Queueable;
  // ...
}

After that, send the notification as usual, and the ShouldQueue interface will automatically queue its delivery. There is a delay method if you need to postpone the delivery. Connect it to the instantiation of your notification as follows:

$when = now()->addMinutes(10);
$user->notify((new StatusUpdate($sale))->delay($when));

How to Run Email Notification Tests

Once you've configured your email notifications, you should test this feature. And, because MailSlurp is used as the default SMTP method in Laravel, you don't have to send actual notifications. This service includes a dummy mailbox that receives email notifications sent by your app. There is no need to tinker with the code of your app. All you have to do is add your MailSlurp credentials to the .env file, so it looks like this:

MAIL_MAILER=smtp
MAIL_HOST=mx.mailslurp.com
MAIL_PORT=2525
MAIL_USERNAME=<username> //your MailSlurp username
MAIL_PASSWORD=<password> // your MailSlurp password
MAIL_ENCRYPTION=false
MAIL_FROM_ADDRESS=from@example.com
MAIL_FROM_NAME=Example

Following that, all email notifications sent from your app will be routed to the MailSlurp Demo Inbox. You'll also be able to check your notifications for spam and preview them to see how they look in different email clients.

Notification Faking

Aside from MailSlurp, you can use the Notification facade's fake method. It simulates the mail delivery process and allows you to confirm whether an email would have arrived in the recipient's inbox. Check out how it works:

<?php
namespace App\Notifications;
use App\User;
use App\Notifications\StatusUpdate;
use Illuminate\Support\Facades\Notification;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class StatusUpdate extends User
{
  public function testStatusOrder()
  {
    Notification::fake();
    // Perform status order...

    Notification::assertSentTo(
      $user,
      StatusOrder::class,
      function ($notification, $channels) use ($sale) {
        // retrieve the mail content
        $mailData = $notification->toMail($user)->toArray();
        $this->assertEquals("Order #{$sale->saleNumber} sold", $mailData['subject']);
        $this->assertEquals("Hello {$user->name}!", $mailData['greeting']);
        $this->assertContains("Your item #{$sale->saleNumber} has been sold", $mailData['introLines']);
        $this->assertEquals("View items", $mailData['actionText']);
        $this->assertEquals(route('orders.show', $sale), $mailData['actionUrl']);
        $this->assertContains("Thanks!", $mailData['outroLines']);
        return $notification->order->id === $sale->id;
      }
    );
  }
}

Various assertions are shown here to test the mail content. They are generated after the code under test has been executed.

Conclusion

Finally, how can you make the most of your email notifications? Email notifications should not be disabled in your app. They increase your customers' LTV as well as their retention rate. As a result, you must ensure not only that they work properly, but also that they are of high quality and valid. Test your notifications end-to-end using real email addresses and SMS sandboxes with MailSlurp.

Related content

PHP

PHP email API for creating inboxes, sending email, and receiving attachments in code and tests.

How to wait for Selenium to start during Codeception tests

Example tutorial for how to wait until webdriver and Selenium have started during Codeception PHP tests

How to use Laravel's notification system (PHP tutorial)

Check new notifications queued in PHP using Laravel's email and SMS notification system.

Codeception PHP acceptance testing using real email address APIs

Write acceptance tests in PHP with real email addresses using Codeception and MailSlurp

PHP Email Test Plugins: send and receive email in PHPUnit (example code)

How to send and receive emails in PHPUnit tests.

Receive email in PHP: using MailSlurp to send and receive emails

Test email in PHP using real email addresses

Send SMTP emails with PHP

Use PHPMailer to send emails with SMTP and MailSlurp

Ready to dive in?Start building email applications today.