To send an email via a notification in Laravel 13, generate a notification class with php artisan make:notification, return ['mail'] from its via() method, build the message in toMail() with a MailMessage, and call $user->notify(new YourNotification()). Implement ShouldQueue on the class so the email is sent in the background.
Notifications are my default for short, transactional emails like "your order shipped" or "your invoice was paid". You write the content once, and later you can add Slack, SMS or database delivery to the same class without touching the code that triggers it.
Prerequisites
- Laravel 13.x on PHP 8.3 or newer.
- A working mailer in
.env. During development,MAIL_MAILER=logwrites emails tostorage/logs/laravel.loginstead of sending them. - A queue connection if you want background delivery. The default
databasedriver is fine to start. - A notifiable model. The default
Usermodel already uses theNotifiabletrait.
Step 1: Generate the notification
php artisan make:notification OrderShippedThis creates app/Notifications/OrderShipped.php.
Step 2: Build the mail message
Pass the data the email needs through the constructor. Laravel serializes Eloquent models in queued notifications by their ID and reloads them when the job runs, so passing a model is cheap.
<?php
namespace App\Notifications;
use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class OrderShipped extends Notification implements ShouldQueue
{
use Queueable;
public function __construct(public Order $order)
{
$this->afterCommit();
}
/**
* @return array<int, string>
*/
public function via(object $notifiable): array
{
return ['mail'];
}
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject("Order #{$this->order->id} is on its way")
->greeting("Hi {$notifiable->name},")
->line('Good news: your order has left our warehouse.')
->lineIf($this->order->tracking_number !== null, "Tracking number: {$this->order->tracking_number}")
->action('Track your order', route('orders.show', $this->order))
->line('Thanks for shopping with us.');
}
}A few notes on the builder methods:
subject()overrides the default subject, which is the class name in title case ("Order Shipped").action()renders a button. Call->error()on the message to render it red for failure emails.lineIf()adds a line only when the condition is true, which keeps the method free of if-blocks.afterCommit()in the constructor makes the queued job wait until any open database transaction commits, so the worker never reads an order that was rolled back.
Step 3: Send the notification
Call notify() on any model that uses the Notifiable trait:
$order->user->notify(new OrderShipped($order));To notify several users at once, use the facade:
use Illuminate\Support\Facades\Notification;
Notification::send($admins, new OrderShipped($order));Because the class implements ShouldQueue, both calls push a job to the queue and return immediately. Start a worker to process it:
php artisan queue:workHow do I send a notification to an email address that is not a user?
Use an on-demand notification. This is handy for guest checkouts or a fixed operations mailbox:
use Illuminate\Support\Facades\Notification;
Notification::route('mail', ['ops@example.com' => 'Operations'])
->notify(new OrderShipped($order));Inside toMail(), $notifiable is then an AnonymousNotifiable without a name property, so guard any user-specific fields when a notification can be sent both ways.
How do I change which address the email goes to?
By default the mail channel uses the model's email attribute. Override it on the model with routeNotificationForMail():
use Illuminate\Notifications\Notification;
public function routeNotificationForMail(Notification $notification): array|string
{
return [$this->billing_email ?? $this->email => $this->name];
}Can I use my own email design?
Yes. Return (new MailMessage)->markdown('mail.order.shipped', ['order' => $this->order]) to render a Markdown template with Laravel's mail components, or ->view() for a plain Blade view. You can also return a full Mailable from toMail() if you already have one.
What does the default notification email look like?
Laravel renders MailMessage content into a responsive HTML template with a header showing your APP_NAME, the greeting, your lines, a centered button for the action, a closing "Regards" line and a small footer with the plain action URL for clients that block buttons. A plain-text version is generated automatically. To change the colours, logo or footer for every notification, publish the templates with php artisan vendor:publish --tag=laravel-notifications and php artisan vendor:publish --tag=laravel-mail, then edit the files under resources/views/vendor. Keep the content short: notifications work best when the email has one clear purpose and one action.
Common mistakes
- No queue worker running. With
ShouldQueueand no worker, nothing is sent. Check thejobstable, andfailed_jobsfor errors. - Stale code in workers. Workers keep the app in memory. Run
php artisan queue:restartafter each deployment. - Wrong
APP_URL. Links built withroute()inside queued notifications useAPP_URL, so set it correctly in production. - Heavy work in the constructor. Compute values in
toMail(), which runs on the worker, not in the request.
How to verify it works
For a quick manual check, set MAIL_MAILER=log, trigger the notification and read the rendered HTML in the log. For automated checks, fake notifications in a Pest test:
<?php
use App\Models\Order;
use App\Notifications\OrderShipped;
use Illuminate\Support\Facades\Notification;
it('notifies the customer when an order ships', function () {
Notification::fake();
$order = Order::factory()->create();
$this->post(route('orders.ship', $order))->assertRedirect();
Notification::assertSentTo(
$order->user,
OrderShipped::class,
fn (OrderShipped $notification) => $notification->order->is($order),
);
});For on-demand recipients use Notification::assertSentOnDemand(OrderShipped::class).
FAQ
Notification or Mailable: which should I use?
Use a notification for short transactional messages that might later go to more channels. Use a Mailable for richly designed emails, newsletters or messages with many attachments.
Can I delay a notification email?
Yes. Call ->delay(now()->addMinutes(10)) on the notification instance before passing it to notify().
Can I send to mail and database at the same time?
Return ['mail', 'database'] from via() and add a toArray() method for the database payload.



