Notifications
Introduction
In addition to support for sending email, Laravel provides support for sending notifications across a variety of delivery channels, including email, SMS (via Vonage, formerly known as Nexmo), and Slack. In addition, a variety of community built notification channels have been created to send notifications over dozens of different channels! Notifications may also be stored in a database so they may be displayed in your web interface.
Typically, notifications should be short, informational messages that notify users of something that occurred in your application. For example, if you are writing a billing application, you might send an "Invoice Paid" notification to your users via the email and SMS channels.
Generating Notifications
In Laravel, each notification is represented by a single class that is typically stored in the app/Notifications directory. Don't worry if you don't see this directory in your application - it will be created for you when you run the make:notification Artisan command:
php artisan make:notification InvoicePaid
This command will place a fresh notification class in your app/Notifications directory. Each notification class contains a via method and a variable number of message building methods, such as toMail or toDatabase, that convert the notification to a message tailored for that particular channel.
Sending Notifications
Using the Notifiable Trait
Notifications may be sent in two ways: using the notify method of the Notifiable trait or using the Notification facade. The Notifiable trait is included on your application's App\Models\User model by default:
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
}
The notify method that is provided by this trait expects to receive a notification instance:
use App\Notifications\InvoicePaid;
$user->notify(new InvoicePaid($invoice));
Remember, you may use the Notifiable trait on any of your models. You are not limited to only including it on your User model.
Using the Notification Facade
Alternatively, you may send notifications via the Notification facade. This approach is useful when you need to send a notification to multiple notifiable entities such as a collection of users. To send notifications using the facade, pass all of the notifiable entities and the notification instance to the send method:
use Illuminate\Support\Facades\Notification;
Notification::send($users, new InvoicePaid($invoice));
You can also send notifications immediately using the sendNow method. This method will send the notification immediately even if the notification implements the ShouldQueue interface:
Notification::sendNow($developers, new DeploymentCompleted($deployment));
Specifying Delivery Channels
Every notification class has a via method that determines on which channels the notification will be delivered. Notifications may be sent on the mail, database, broadcast, vonage, and slack channels.
If you would like to use other delivery channels such as Telegram or Pusher, check out the community driven Laravel Notification Channels website.
The via method receives a $notifiable instance, which will be an instance of the class to which the notification is being sent. You may use $notifiable to determine which channels the notification should be delivered on:
/**
* Get the notification's delivery channels.
*
* @return array<int, string>
*/
public function via(object $notifiable): array
{
return $notifiable->prefers_sms ? ['vonage'] : ['mail', 'database'];
}
Queueing Notifications
Before queueing notifications you should configure your queue and start a worker.
Sending notifications can take time, especially if the channel needs to make an external API call to deliver the notification. To speed up your application's response time, let your notification be queued by adding the ShouldQueue interface and Queueable trait to your class. The interface and trait are already imported for all notifications generated using the make:notification command, so you may immediately add them to your notification class:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
class InvoicePaid extends Notification implements ShouldQueue
{
use Queueable;
// ...
}
Once the ShouldQueue interface has been added to your notification, you may send the notification like normal. Laravel will detect the ShouldQueue interface on the class and automatically queue the delivery of the notification:
$user->notify(new InvoicePaid($invoice));
When queueing notifications, a queued job will be created for each recipient and channel combination. For example, six jobs will be dispatched to the queue if your notification has three recipients and two channels.
Delaying Notifications
If you would like to delay the delivery of the notification, you may chain the delay method onto your notification instantiation:
$delay = now()->addMinutes(10);
$user->notify((new InvoicePaid($invoice))->delay($delay));
You may pass an array to the delay method to specify the delay amount for specific channels:
$user->notify((new InvoicePaid($invoice))->delay([
'mail' => now()->addMinutes(5),
'sms' => now()->addMinutes(10),
]));
Alternatively, you may define a withDelay method on the notification class itself. The withDelay method should return an array of channel names and delay values:
/**
* Determine the notification's delivery delay.
*
* @return array<string, \Illuminate\Support\Carbon>
*/
public function withDelay(object $notifiable): array
{
return [
'mail' => now()->addMinutes(5),
'sms' => now()->addMinutes(10),
];
}
Customizing the Notification Queue Connection
By default, queued notifications will be queued using your application's default queue connection. If you would like to specify a different connection that should be used for a particular notification, you may call the onConnection method from your notification's constructor:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
class InvoicePaid extends Notification implements ShouldQueue
{
use Queueable;
/**
* Create a new notification instance.
*/
public function __construct()
{
$this->onConnection('redis');
}
}
Or, if you would like to specify a specific queue connection that should be used for each notification channel supported by the notification, you may define a viaConnections method on your notification. This method should return an array of channel name / queue connection name pairs:
/**
* Determine which connections should be used for each notification channel.
*
* @return array<string, string>
*/
public function viaConnections(): array
{
return [
'mail' => 'redis',
'database' => 'sync',
];
}
Customizing Notification Channel Queues
If you would like to specify a specific queue that should be used for each notification channel supported by the notification, you may define a viaQueues method on your notification. This method should return an array of channel name / queue name pairs:
/**
* Determine which queues should be used for each notification channel.
*
* @return array<string, string>
*/
public function viaQueues(): array
{
return [
'mail' => 'mail-queue',
'slack' => 'slack-queue',
];
}
Queued Notification Middleware
Queued notifications may define middleware just like queued jobs. To get started, define a middleware method on your notification class. The middleware method will receive $notifiable and $channel variables, which allow you to customize the returned middleware based on the notification's destination:
use Illuminate\Queue\Middleware\RateLimited;
/**
* Get the middleware the notification job should pass through.
*
* @return array<int, object>
*/
public function middleware(object $notifiable, string $channel)
{
return match ($channel) {
'email' => [new RateLimited('postmark')],
'slack' => [new RateLimited('slack')],
default => [],
};
}
Queued Notifications and Database Transactions
When queued notifications are dispatched within database transactions, they may be processed by the queue before the database transaction has committed. When this happens, any updates you have made to models or database records during the database transaction may not yet be reflected in the database. In addition, any models or database records created within the transaction may not exist in the database. If your notification depends on these models, unexpected errors can occur when the job that sends the queued notification is processed.
If your queue connection's after_commit configuration option is set to false, you may still indicate that a particular queued notification should be dispatched after all open database transactions have been committed by calling the afterCommit method when sending the notification:
use App\Notifications\InvoicePaid;
$user->notify((new InvoicePaid($invoice))->afterCommit());
Alternatively, you may call the afterCommit method from your notification's constructor:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
class InvoicePaid extends Notification implements ShouldQueue
{
use Queueable;
/**
* Create a new notification instance.
*/
public function __construct()
{
$this->afterCommit();
}
}
To learn more about working around these issues, please review the documentation regarding queued jobs and database transactions.
Determining if a Queued Notification Should Be Sent
After a queued notification has been dispatched for the queue for background processing, it will typically be accepted by a queue worker and sent to its intended recipient.
However, if you would like to make the final determination on whether the queued notification should be sent after it is being processed by a queue worker, you may define a shouldSend method on the notification class. If this method returns false, the notification will not be sent:
/**
* Determine if the notification should be sent.
*/
public function shouldSend(object $notifiable, string $channel): bool
{
return $this->invoice->isPaid();
}
On-Demand Notifications
Sometimes you may need to send a notification to someone who is not stored as a "user" of your application. Using the Notification facade's route method, you may specify ad-hoc notification routing information before sending the notification:
use Illuminate\Broadcasting\Channel;
use Illuminate\Support\Facades\Notification;
Notification::route('mail', 'taylor@example.com')
->route('vonage', '5555555555')
->route('slack', '#slack-channel')
->route('broadcast', [new Channel('channel-name')])
->notify(new InvoicePaid($invoice));
If you would like to provide the recipient's name when sending an on-demand notification to the mail route, you may provide an array that contains the email address as the key and the name as the value of the first element in the array:
Notification::route('mail', [
'barrett@example.com' => 'Barrett Blair',
])->notify(new InvoicePaid($invoice));
Using the routes method, you may provide ad-hoc routing information for multiple notification channels at once:
Notification::routes([
'mail' => ['barrett@example.com' => 'Barrett Blair'],
'vonage' => '5555555555',
])->notify(new InvoicePaid($invoice));
Mail Notifications
Formatting Mail Messages
If a notification supports being sent as an email, you should define a toMail method on the notification class. This method will receive a $notifiable entity and should return an Illuminate\Notifications\Messages\MailMessage instance.
The MailMessage class contains a few simple methods to help you build transactional email messages. Mail messages may contain lines of text as well as a "call to action". Let's take a look at an example toMail method:
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
$url = url('/invoice/'.$this->invoice->id);
return (new MailMessage)
->greeting('Hello!')
->line('One of your invoices has been paid!')
->lineIf($this->amount > 0, "Amount paid: {$this->amount}")
->action('View Invoice', $url)
->line('Thank you for using our application!');
}
Note we are using $this->invoice->id in our toMail method. You may pass any data your notification needs to generate its message into the notification's constructor.
In this example, we register a greeting, a line of text, a call to action, and then another line of text. These methods provided by the MailMessage object make it simple and fast to format small transactional emails. The mail channel will then translate the message components into a beautiful, responsive HTML email template with a plain-text counterpart. Here is an example of an email generated by the mail channel:
When sending mail notifications, be sure to set the name configuration option in your config/app.php configuration file. This value will be used in the header and footer of your mail notification messages.
Error Messages
Some notifications inform users of errors, such as a failed invoice payment. You may indicate that a mail message is regarding an error by calling the error method when building your message. When using the error method on a mail message, the call to action button will be red instead of black:
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->error()
->subject('Invoice Payment Failed')
->line('...');
}
Other Mail Notification Formatting Options
Instead of defining the "lines" of text in the notification class, you may use the view method to specify a custom template that should be used to render the notification email:
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)->view(
'mail.invoice.paid', ['invoice' => $this->invoice]
);
}
You may specify a plain-text view for the mail message by passing the view name as the second element of an array that is given to the view method:
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)->view(
['mail.invoice.paid', 'mail.invoice.paid-text'],
['invoice' => $this->invoice]
);
}
Or, if your message only has a plain-text view, you may utilize the text method:
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)->text(
'mail.invoice.paid-text', ['invoice' => $this->invoice]
);
}
Customizing the Sender
By default, the email's sender / from address is defined in the config/mail.php configuration file. However, you may specify the from address for a specific notification using the from method:
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->from('barrett@example.com', 'Barrett Blair')
->line('...');
}
Customizing the Recipient
When sending notifications via the mail channel, the notification system will automatically look for an email property on your notifiable entity. You may customize which email address is used to deliver the notification by defining a routeNotificationForMail method on the notifiable entity:
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Notifications\Notification;
class User extends Authenticatable
{
use Notifiable;
/**
* Route notifications for the mail channel.
*
* @return array<string, string>|string
*/
public function routeNotificationForMail(Notification $notification): array|string
{
// Return email address only...
return $this->email_address;
// Return email address and name...
return [$this->email_address => $this->name];
}
}
Customizing the Subject
By default, the email's subject is the class name of the notification formatted to "Title Case". So, if your notification class is named InvoicePaid, the email's subject will be Invoice Paid. If you would like to specify a different subject for the message, you may call the subject method when building your message:
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject('Notification Subject')
->line('...');
}
Customizing the Mailer
By default, the email notification will be sent using the default mailer defined in the config/mail.php configuration file. However, you may specify a different mailer at runtime by calling the mailer method when building your message:
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->mailer('postmark')
->line('...');
}
Customizing the Templates
You can modify the HTML and plain-text template used by mail notifications by publishing the notification package's resources. After running this command, the mail notification templates will be located in the resources/views/vendor/notifications directory:
php artisan vendor:publish --tag=laravel-notifications
Attachments
To add attachments to an email notification, use the attach method while building your message. The attach method accepts the absolute path to the file as its first argument:
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->greeting('Hello!')
->attach('/path/to/file');
}
The attach method offered by notification mail messages also accepts attachable objects. Please consult the comprehensive attachable object documentation to learn more.
When attaching files to a message, you may also specify the display name and / or MIME type by passing an array as the second argument to the attach method:
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->greeting('Hello!')
->attach('/path/to/file', [
'as' => 'name.pdf',
'mime' => 'application/pdf',
]);
}
Unlike attaching files in mailable objects, you may not attach a file directly from a storage disk using attachFromStorage. You should rather use the attach method with an absolute path to the file on the storage disk. Alternatively, you could return a mailable from the toMail method:
use App\Mail\InvoicePaid as InvoicePaidMailable;
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): Mailable
{
return (new InvoicePaidMailable($this->invoice))
->to($notifiable->email)
->attachFromStorage('/path/to/file');
}
When necessary, multiple files may be attached to a message using the attachMany method:
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->greeting('Hello!')
->attachMany([
'/path/to/forge.svg',
'/path/to/vapor.svg' => [
'as' => 'Logo.svg',
'mime' => 'image/svg+xml',
],
]);
}
Raw Data Attachments
The attachData method may be used to attach a raw string of bytes as an attachment. When calling the attachData method, you should provide the filename that should be assigned to the attachment:
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->greeting('Hello!')
->attachData($this->pdf, 'name.pdf', [
'mime' => 'application/pdf',
]);
}
Adding Tags and Metadata
Some third-party email providers such as Mailgun and Postmark support message "tags" and "metadata", which may be used to group and track emails sent by your application. You may add tags and metadata to an email message via the tag and metadata methods:
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->greeting('Comment Upvoted!')
->tag('upvote')
->metadata('comment_id', $this->comment->id);
}
If your application is using the Mailgun driver, you may consult Mailgun's documentation for more information on tags and metadata. Likewise, the Postmark documentation may also be consulted for more information on their support for tags and metadata.
If your application is using Amazon SES to send emails, you should use the metadata method to attach SES "tags" to the message.
Customizing the Symfony Message
The withSymfonyMessage method of the MailMessage class allows you to register a closure which will be invoked with the Symfony Message instance before sending the message. This gives you an opportunity to deeply customize the message before it is delivered:
use Symfony\Component\Mime\Email;
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->withSymfonyMessage(function (Email $message) {
$message->getHeaders()->addTextHeader(
'Custom-Header', 'Header Value'
);
});
}
Using Mailables
If needed, you may return a full mailable object from your notification's toMail method. When returning a Mailable instead of a MailMessage, you will need to specify the message recipient using the mailable object's to method:
use App\Mail\InvoicePaid as InvoicePaidMailable;
use Illuminate\Mail\Mailable;
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): Mailable
{
return (new InvoicePaidMailable($this->invoice))
->to($notifiable->email);
}
Mailables and On-Demand Notifications
If you are sending an on-demand notification, the $notifiable instance given to the toMail method will be an instance of Illuminate\Notifications\AnonymousNotifiable, which offers a routeNotificationFor method that may be used to retrieve the email address the on-demand notification should be sent to:
use App\Mail\InvoicePaid as InvoicePaidMailable;
use Illuminate\Notifications\AnonymousNotifiable;
use Illuminate\Mail\Mailable;
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): Mailable
{
$address = $notifiable instanceof AnonymousNotifiable
? $notifiable->routeNotificationFor('mail')
: $notifiable->email;
return (new InvoicePaidMailable($this->invoice))
->to($address);
}
Previewing Mail Notifications
When designing a mail notification template, it is convenient to quickly preview the rendered mail message in your browser like a typical Blade template. For this reason, Laravel allows you to return any mail message generated by a mail notification directly from a route closure or controller. When a MailMessage is returned, it will be rendered and displayed in the browser, allowing you to quickly preview its design without needing to send it to an actual email address:
use App\Models\Invoice;
use App\Notifications\InvoicePaid;
Route::get('/notification', function () {
$invoice = Invoice::find(1);
return (new InvoicePaid($invoice))
->toMail($invoice->user);
});
Markdown Mail Notifications
Markdown mail notifications allow you to take advantage of the pre-built templates of mail notifications, while giving you more freedom to write longer, customized messages. Since the messages are written in Markdown, Laravel is able to render beautiful, responsive HTML templates for the messages while also automatically generating a plain-text counterpart.
Generating the Message
To generate a notification with a corresponding Markdown template, you may use the --markdown option of the make:notification Artisan command:
php artisan make:notification InvoicePaid --markdown=mail.invoice.paid
Like all other mail notifications, notifications that use Markdown templates should define a toMail method on their notification class. However, instead of using the line and action methods to construct the notification, use the markdown method to specify the name of the Markdown template that should be used. An array of data you wish to make available to the template may be passed as the method's second argument:
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
$url = url('/invoice/'.$this->invoice->id);
return (new MailMessage)
->subject('Invoice Paid')
->markdown('mail.invoice.paid', ['url' => $url]);
}
Writing the Message
Markdown mail notifications use a combination of Blade components and Markdown syntax which allow you to easily construct notifications while leveraging Laravel's pre-crafted notification components:
<x-mail::message>
# Invoice Paid
Your invoice has been paid!
<x-mail::button :url="$url">
View Invoice
</x-mail::button>
Thanks,<br>
{{ config('app.name') }}
</x-mail::message>
Button Component
The button component renders a centered button link. The component accepts two arguments, a url and an optional color. Supported colors are primary, green, and red. You may add as many button components to a notification as you wish:
<x-mail::button :url="$url" color="green">
View Invoice
</x-mail::button>
Panel Component
The panel component renders the given block of text in a panel that has a slightly different background color than the rest of the notification. This allows you to draw attention to a given block of text:
<x-mail::panel>
This is the panel content.
</x-mail::panel>
Table Component
The table component allows you to transform a Markdown table into an HTML table. The component accepts the Markdown table as its content. Table column alignment is supported using the default Markdown table alignment syntax:
<x-mail::table>
| Laravel | Table | Example |
| ------------- | :-----------: | ------------: |
| Col 2 is | Centered | $10 |
| Col 3 is | Right-Aligned | $20 |
</x-mail::table>
Customizing the Components
You may export all of the Markdown notification components to your own application for customization. To export the components, use the vendor:publish Artisan command to publish the laravel-mail asset tag:
php artisan vendor:publish --tag=laravel-mail
This command will publish the Markdown mail components to the resources/views/vendor/mail directory. The mail directory will contain an html and a text directory, each containing their respective representations of every available component. You are free to customize these components however you like.
Customizing the CSS
After exporting the components, the resources/views/vendor/mail/html/themes directory will contain a default.css file. You may customize the CSS in this file and your styles will automatically be in-lined within the HTML representations of your Markdown notifications.
If you would like to build an entirely new theme for Laravel's Markdown components, you may place a CSS file within the html/themes directory. After naming and saving your CSS file, update the theme option of the mail configuration file to match the name of your new theme.
To customize the theme for an individual notification, you may call the theme method while building the notification's mail message. The theme method accepts the name of the theme that should be used when sending the notification:
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->theme('invoice')
->subject('Invoice Paid')
->markdown('mail.invoice.paid', ['url' => $url]);
}
Database Notifications
Prerequisites
The database notification channel stores the notification information in a database table. This table will contain information such as the notification type as well as a JSON data structure that describes the notification.
You can query the table to display the notifications in your application's user interface. But, before you can do that, you will need to create a database table to hold your notifications. You may use the make:notifications-table command to generate a migration with the proper table schema:
php artisan make:notifications-table
php artisan migrate