26 min read

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.

Tim Davidson
Author
Tim Davidson

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',
    );
}

Enjoying this post? Get more delivered to your inbox!

Enter your email to get a monthly round up of technology tips and news.

    We won't send you spam. Unsubscribe at any time.

    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 withmethod:

    <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.

    MAIL_DRIVER=smtp
    MAIL_HOST=smtp.mailtrap.io
    MAIL_PORT=2525
    MAIL_USERNAME= //your username generated by Mailtrap
    MAIL_PASSWORD= // your password generated by Mailtrap
    MAIL_FROM_ADDRESS=from@example.com
    MAIL_FROM_NAME=Example
    .env file configuration

    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.

    Written by
    Tim Davidson

    Tim Davidson

    Tim is the face of the company. When you want to kick off a new project, or an update on your existing project, Tim is your man!

    Read more on the subject

    Customer Experience (CX) - Why It Pays To Invest In CX

    Tim Davidson

    Is Mobile First Always The Best Approach?

    Patryk Michalski

    Digital Product Design Process

    Tim Davidson

    Don’t miss out on the latest stories!

    Sign up for my newsletter to receive the latest news from the blog, you’ll get pinged every few months with a digest from the tech world.

    Thank you for reaching out!