Laravel 10.x - Send email with SMTP

Laravel 10.x - Send email with SMTP

2023-09-08
4 min read

Introduction

The article is using Laravel 10.x. There could be errors in lower versions.

.env and configuration

Before getting started, .env config need to be changed.

.env

text
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=465
MAIL_USERNAME=mygoogle@gmail.com
MAIL_PASSWORD=mygooglepassword
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=mygoogle@gmail.com
MAIL_FROM_NAME="${APP_NAME}"

The mail system uses data in .env on default. The configuration file will be config/mail.php.

Generate Mailable

bash
php artisan make:mail Invoice

If you run above command, a class would be created extended by Mailable. The file is in app/mail/Invoice.php.

Example Code

php
<?php
  
namespace App\Mail;
  
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
  
class Invoice extends Mailable
{
    use Queueable, SerializesModels;
  
    public $name;
    public $attachemnts;
  
    /**
     * Create a new message instance.
     */
    public function __construct($name, $attachemnts)
    {
        $this->name = $name;
        $this->attachemnts = $attachemnts;
    }
  
    /**
     * Get the message envelope.
     */
    public function envelope(): Envelope
    {
        return new Envelope(
            subject: 'Demo Mail',
        );
    }
  
    /**
     * Get the message content definition.
     */
    public function content(): Content
    {
        return new Content(
            view: 'emails.demoMail',
        );
    }
  
    /**
     * Get the attachments for the message.
     *
     * @return array
     */
    public function attachments(): array
    {
        $result = array();
        if ($this->attachemnts) {
            foreach ($this->attachments as $attachment) 
            {
                array_push($result, Attachment::fromPath(public_path('storage') . '/' . $attachment->name),);
            }
        }

        return $result;
    }
}

For explanation, change code like above.

Methods

Following methods are key configuration that you should know.

NameDescription
EnvelopeDefines subject, email and repliers
ContentDefines the blade template for content of email
AttachmentAdd attachments to email

Envelope

The envelope() method defines sender configurations like from, replyTo and subject, and it returns Envelope class.

Property

NameDescirption
fromSet sender. It will be set data in .env on default
replyToSet additional to. It takes array.
subjectSet title of email
tagsAdd tags. It takes array.
metadataAdd metatags. It takes array.

How to use

php
return new Envelope(
    from: new Address('abc@example.com', 'Xyz'),
    replyTo: [
        new Address('xyz@example.com', 'Xyz'),
    ],
    subject: 'Invoice for #123123',
    tags: ['invoice'],
    metadata: [
        'invoiceId' => $this->invoice->id,
    ],
);

The Address class should be used in order to from and element in replyTo,

replyTo global

The replyTo can be set globally in config/mail.php

php
'reply_to' => ['address' => 'example@example.com', 'name' => 'App Name'],

Content

The content() method renders view with some data. The content() method returns Content class

How to use

php
public function content(): Content
{
    return new Content(
        markdown: 'emails.invoice',
        with: [
            'today' => date('Y/m/d')
        ]
    );
}

Property

NameDescription
viewLoad blade template as html from path
markdownLoad blade template as Markdown from path
withAllows to use more variables not only in class variables

Views (Template)

php mail supports html, plain text and markdown file with blade template. The Path is passed to view, replaced / to .. It uses /rosources on default, so resousces is not required in string. For example, the path is emails.invoice if the template file is in resources/views/emails and name is invoice.blade.php.

Markdown

php
@component('mail::message')
Hello {{$name}}

Here is inovice:

Thanks,<br>
{{ config('app.name') }}
@endcomponent

The components like Button, panel and table can be used.

php
<x-mail::button :url="$url" color="success">
Button
</x-mail::button>

<x-mail::table>
| Col1  |     Col2      | Price |
| ----- | :-----------: | ----: |
| Row 1 |   Centered    |   $10 |
| Row 2 | Right-Aligned |   $20 |
</x-mail::table>

<x-mail::panel>
Panel content
</x-mail::panel>

Attachments

The attachments() method adds attachments, returned an array to email. It returns array of Attachment class

php
public function attachments(): array
{
    $result = array();
    if ($this->attachemnts) {
        foreach ($this->attachments as $attachment) 
        {
            array_push($result, Attachment::fromPath(public_path('storage') . '/' . $attachment->name),);
        }
    }

    return $result;
}

The Attachment class provides three methods.

NameDescription
fromPath()from path
fromStorage()from filesystem disks
fromStorageDisk()from specific storage disk

Click the link to see more detail about filesysstem in Laravel

Name / MIME

The file Name and Mime type for attachments can be modified by using as and withMime Methods.

php
Attachment::fromPath('/path/to/file')
                ->as('name.pdf')
                ->withMime('application/pdf'),

Click the link to see about mime type.

Controller

If you don't have controller, run the below command to create a mail controller

bash
php artisan make:controller EmailController

Before using Mail, Import Mail at the top.

php
public function sendEmail(Request $request)
{
    $request->validate([
        'email' => 'required|string|email|max:255',
        'name' => 'required|string|max:255'
    ]);

    // send email
    Mail::to($request->email)->send(new InvoiceMail(
        $request->name,
        [],
    ));

    return response()->json([
        'message' => 'Successfully sent',
    ]);
}

Add email to send in to() method. The Send() method should take Mailable class along with parameter.

Add CC

The header allows to add CC, but cc can be added for each controller.

php
Mail::to($request->email)
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->send(new InvoiceMail(
        $request->name,
        [],
    ));

Send many messages at the same time

Use queue method instead of send. The queue allows to add mail job into queue.

If you would like to make Mailable class always in queue, implement ShouldQueue .

php
class InvoiceMail extends Mailable implements ShouldQueue
{
    //
}

Ref

Free open source project made by Youngjin