Sending Emails in Laravel: Mailable Classes, Templates & Laravel Versions
For creating apps with PHP, software engineers may choose Laravel, a PHP framework that optimizes emailing processes. Laravel allows you to manage email previews, has various options for localization, and ensures that real users never see test emails in their inboxes.
The available documentation and tutorials cover most of the questions on managing emails in Laravel. Still, new releases and constant updates may cause questions. So let's go through the most frequent ones: how to send emails in Laravel, and manage mailable classes and Blade templates.
Сreating Mailable Class
Each type of email sent in Laravel is presented as a mailable class. It is stored in app/Mail
directory that is automatically generated as soon as the class is created using the make:mail
Artisan command:
php artisan make:mail OrderShipped
Configuration for mailables is done in several methods — envelope
, content
, and attachments
.
Configuring The Sender
Using The Envelope
In Laravel, we have two ways to configure the sender.
Firstly, it may be specified on the message's envelope:
use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Envelope;
/**
* Get the message envelope.
*
* @return \\Illuminate\\Mail\\Mailables\\Envelope
*/
public function envelope()
{
return new Envelope(
from: new Address('jeffrey@example.com', 'Jeffrey Way'),
subject: 'Order Shipped',
);
}
Using a Global from
Address
When your application has the same sender address for all the emails, you may specify an address in the config/mail.php
configuration file. If there is no fixed "from" address within the mailable class, the system will use this one:
'from' => [
'address' => 'example@example.com',
'name' => 'App Name'
],
Use global "reply_to" address within config/mail.php
file:
'reply_to' => [
'address' => 'example@example.com',
'name' => 'App Name'
],
Configuring The View
You may define the view
or the template needed to be used when rendering the email's contents within the content
method:
/**
* Get the message content definition.
*
* @return \Illuminate\Mail\Mailables\Content
*/
public function content()
{
return new Content(
view: 'emails.orders.shipped',
);
}
Plain Text Emails
Specify the plain-text template when creating the Content
definition to define a plain-text version of an email:
/**
* Get the message content definition.
* @return \Illuminate\Mail\Mailables\Content
*/
public function content()
{
return new Content(
view: 'emails.orders.shipped',
text: 'emails.orders.shipped-text'
);
}
You may use the html
parameter as an alias of the view
parameter:
return new Content(
html: 'emails.orders.shipped',
text: 'emails.orders.shipped-text'
);
View Data
You may use one of two to view data:
Via Public Properties
Any public property defined on the mailable class will be available to view automatically.
For instance, pass data into the constructor and set that data to public properties:
<?php
namespace App\Mail;
use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Queue\SerializesModels;
class OrderShipped extends Mailable
{
use Queueable, SerializesModels;
/**
* The order instance.
* @var \App\Models\Order
*/
public $order;
/**
* Create a new message instance.
* @param \App\Models\Order $order
* @return void
*/
public function _construct(Order $order)
{
$this->order = $order;
}
/**
* Get the message content definition.
*
* @return \Illuminate\Mail\Mailables\Content
*/
public function content()
{
return new Content(
view: 'emails.orders.shipped',
);
}
}
When the data is set to public property, you may access it:
<div>
Price: {{ $order->price }}
</div>
Via The with
Parameter
When you need to customize the email's data format before it is delivered to the template, pass the data manually to view via the Content
definitions with
parameter.
Set the data to protected
or private
properties, and the data will no longer be automatically available to the template:
<?php
namespace App\Mail;
use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Queue\SerializesModels;
class OrderShipped extends Mailable
{
use Queueable, SerializesModels;
/**
* The order instance.
* @var \App\Models\Order
*/
protected $order;
/**
* Create a new message instance.
* @param \App\Models\Order $order
* @return void
*/
public function _construct(Order $order)
{
$this->order = $order;
}
/**
* Get the message content definition.
*
* @return \Illuminate\Mail\Mailables\Content
*/
public function content()
{
return new Content(
view: 'emails.orders.shipped',
with: [
'orderName' => $this->order->name,
'orderPrice' => $this->order->price,
],
);
}
}
You may access it as soon as it is passed to the with
method:
<div>
Price: {{ $orderPrice }}
</div>
Attachments
To add attachments to an email, add them to the array returned by the attachments
method.
Firstly, add an attachment — provide a path to the fromPath
method:
use Illuminate\Mail\Mailables\Attachment;
/**
* Get the attachments for the message.
*
* @return \Illuminate\Mail\Mailables\Attachment
*/
public function attachments()
{
return [
Attachment::fromPath('/path/to/file'),
];
}
While attaching files, specify the display name or MIME type — use the as
and withMime
methods:
/**
* Get the attachments for the message.
*
* @return \Illuminate\Mail\Mailables\Attachment
*/
public function attachments()
{
return [Attachment::fromPath('/path/to/file')->as('name.pdf')->withMime('application/pdf')];
}
Attaching Files From Disk
Attach files from filesystem disks using the fromStorage
attachment method:
/**
* Get the attachments for the message.
*
* @return \Illuminate\Mail\Mailables\Attachment\[]
*/
public function attachments()
{
return [
Attachment::fromStorage('/path/to/file'),
];
}
Additionally, specify the name and MIME type for the attachment:
/**
* Get the attachments for the message.
*
* @return \Illuminate\Mail\Mailables\Attachment\[]
*/
public function attachments()
{
return [
Attachment::fromStorage('/path/to/file')
->as('name.pdf')
->withMime('application/pdf'),
];
}
To specify a storage disk use fromStorageDisk
method:
/**
* Get the attachments for the message.
*
* @return \Illuminate\Mail\Mailables\Attachment\[]
*/
public function attachments()
{
return [
Attachment::fromStorageDisk('s3', '/path/to/file')
->as('name.pdf')
->withMime('application/pdf'),
];
}
Raw Data Attachments
To attach raw data, use fromData
method:
/**
* Get the attachments for the message.
*
* @return \Illuminate\Mail\Mailables\Attachment\[]
*/
public function attachments()
{
return [
Attachment::fromData(fn () => $this->pdf, 'Report.pdf')
->withMime('application/pdf'),
];
}
Inline Attachments
To embed an image, use the embed
method.
The system automatically makes the $message
variable for all templates:
<body>
Here is an image:
<img src="{{ $message->embed($pathToImage) }}">
</body>
Headers
To attach additional headlines, define a headers
method. It will return Illuminate\Mail\Mailables\Headers
instance:
use Illuminate\Mail\Mailables\Headers;
/**
* Get the message headers.
* @return \Illuminate\Mail\Mailables\Headers
*/
public function headers()
{
return new Headers(
messageId: 'custom-message-id@example.com',
references: ['previous-message@example.com'\],
text: [
'X-Custom-Header' => 'Custom Value',
],
);
}
Tags & Metadata
Add tags and metadata via Envelope
definition:
use Illuminate\Mail\Mailables\Envelope;
/**
* Get the message envelope.
*
* @return \Illuminate\Mail\Mailables\Envelope
*/
public function envelope()
{
return new Envelope(
subject: 'Order Shipped',
tags: ['shipment'],
metadata: [
'order_id' => $this->order->id,
],
);
}
Working with Laravel Mail
Creating the Laravel Email Template
With Laravel, you can create templates, including buttons, tables, and panels — a rare feature for other frameworks' markdown support. The template is a fully customizable Blade file.
Template files use the .blade.php
extension. They are stored in the resources/views
directory.
To return Blade views from routes or controllers, use view
helper
Displaying Data
To display data, use the route:
Route::get('/', function () {
return view('welcome', ['name' => 'Samantha']);
});
Display the contents of the name
variable:
Hello, {{ $name }}.
HTML Entity Encoding
To disable double encoding, use the Blade::withoutDoubleEncoding
method from the boot
method of AppServiceProvider
:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Blade::withoutDoubleEncoding();
}
}
Sending an email with Laravel
To send an email in Laravel, use one of the API-based drivers:
Mailgun, SparkPost, Amazon SES or Mailtrap email API. You may set a default driver in a mail configuration file and manage particular types of messages with SparkPost:
Mail::mailer('sparkpost')
->to($emailAddress())
->send(new NewUserNotification));
Sending Emails Through Laravel using SMTP
You may use any SMTP server, Gmail, for instance. All the configurations are in config/mail.php file.
Laravel recommends using the Mailtrap SMTP server. It ensures that the actual users will never get a test email — to send a message to real users, change the configuration:
MAIL_MAILER=smtp
MAIL_HOST=smtp.googlemail.com
MAIL_PORT=465
MAIL_USERNAME=youremail@gmail.com
MAIL_PASSWORD=your password
MAIL_ENCRYPTION=ssl
Integrate Mailtrap with Laravel
Laravel did work with Mailtrap simple. There is a default Mailtrap server, so you only need to enter credentials. Use Cloudways Managed Hosting Platform to install Laravel and paste the configurations in the .env file.
Laravel Versions
Laravel releases a new version every year. All the versions designated LTS are supported with security fixes for three years and bug fixes for two years.
The 9th version of Laravel was released on February 8, 2022. The 8th version is still maintained; older ones are not updated or maintained. The 10th version may be released on February 7, 2023.