Mail and notifications
A registration confirmation, a receipt after payment, an abandoned-cart reminder — almost every site needs email. In Laravel a message is described by a class and a Blade template, and settings decide how it is delivered.
Configuration
The mail server parameters live in .env:
MAIL_MAILER=smtp
MAIL_HOST=smtp.example.com
MAIL_PORT=587
MAIL_USERNAME=robot@example.com
MAIL_PASSWORD=secret
MAIL_FROM_ADDRESS=robot@example.com
MAIL_FROM_NAME="My blog"During development the value MAIL_MAILER=log is handy: messages are not sent but written to the storage/logs/laravel.log log.
The message class
php artisan make:mail OrderShippednamespace App\Mail;
use App\Models\Order;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
class OrderShipped extends Mailable
{
public function __construct(public Order $order) {}
public function envelope(): Envelope
{
return new Envelope(subject: 'Your order has shipped');
}
public function content(): Content
{
return new Content(view: 'mail.order-shipped');
}
}The public properties of the class are available in the template.
The template
{{-- resources/views/mail/order-shipped.blade.php --}}
<h1>Order #{{ $order->id }} has shipped</h1>
<p>Total: ${{ $order->total }}</p>
<a href="{{ route('orders.show', $order) }}">View the order</a>Sending
use App\Mail\OrderShipped;
use Illuminate\Support\Facades\Mail;
Mail::to($order->user)->send(new OrderShipped($order));to() accepts an address as a string or a user model — Laravel takes its email property.
Through a queue
Connecting to a mail server takes seconds. The queue() method sends the message in the background:
Mail::to($order->user)->queue(new OrderShipped($order));Notifications
A notification is a message that can be delivered in several ways at once: by email, into the database for a bell on the site, to a messenger:
php artisan make:notification InvoicePaidnamespace App\Notifications;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class InvoicePaid extends Notification
{
public function __construct(public int $amount) {}
public function via(object $notifiable): array
{
return ['mail', 'database'];
}
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject('Invoice paid')
->line("We received your payment: \${$this->amount}.")
->action('Open the invoice', url('/invoices'));
}
public function toArray(object $notifiable): array
{
return ['amount' => $this->amount];
}
}It is sent with a method of the user model:
$user->notify(new InvoicePaid(1500));
$unread = $user->unreadNotifications;Common mistake
A message sent during the request delays the response, and if the mail server fails the user sees an error instead of the "Order placed" page. Send mail through a queue — queue() instead of send() — and check how it looks without real delivery, with MAIL_MAILER=log.