Testing Email In Laravel
Tags: laravel, mail, queue
Published: 2024-01-26 07:39:44

## Problem Statement

You might come across to the situation where you need to test your email configuration in your Laravel application - in my case, I need to test the:

- SMTP Connection
- Send E-mail using Queue
- Send E-mail not using Queue

I don't want to test my e-mail by having to go through entire process of my application functions. 

I'm simply want to tackle above 3 use cases.

## Solution

So, let's create an artisan command that be able to send e-mail either using queue or not.

### Mail Class

First thing first, let's create a Mail class:

```bash
php artisan make:mail DefaultMail
```

And I have the following class, which I added a bit of customisation on constructor and few other things.

```php
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Attachment;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;

class DefaultMail extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * Create a new message instance.
     */
    public function __construct(
        public string $title,
        public $message,
        public ?string $url = null,
        public $attachment = null
    ) {
    }

    /**
     * Get the message envelope.
     */
    public function envelope(): Envelope
    {
        return new Envelope(
            subject: $this->title,
        );
    }

    /**
     * Get the message content definition.
     */
    public function content(): Content
    {
        return new Content(
            view: 'mail.default',
            with: [
                'title' => $this->title,
                'content' => $this->message,
                'url' => $this->url,
            ],
        );
    }

    /**
     * Get the attachments for the message.
     *
     * @return array<int, \Illuminate\Mail\Mailables\Attachment>
     */
    public function attachments(): array
    {
        if (empty($this->attachment) || ! file_exists($this->attachment)) {
            return [];
        }

        return [
            Attachment::fromPath($this->attachment),
        ];
    }
}
```

The view:

```php
@component('mail::message')
{{ __('Hi') }},

<p style="text-align: justify">
@foreach($message as $msg)
        <span style="text-align: justify">
            {!! $msg !!}
        </span>
@endforeach
</p>

@if(isset($url) && !empty($url) )
	@component('mail::button', ['url' => $url])
	{{ (isset($url_text) && !empty($url_text)) ? $url_text : __('Click here') }}
	@endcomponent
@endif

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

### Artisan Command

Next, let's create an artisan command:

```bash
php artisan make:command TestSendEmailCommand
```

Then I have the following in the class:

```php
<?php

namespace App\Console\Commands;

use App\Mail\DefaultMail;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;

class TestSendEmailCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'email:test {email} {--queue= : Type of queue - default, mail, notification}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Send test email';

    /**
     * Execute the console command.
     */
    public function handle()
    {
        $email = new DefaultMail('Test Email', 'This is a test email');

        if ($this->option('queue')) {
            Mail::to($this->argument('email'))
                ->queue(
                    $email->onQueue($this->option('queue'))
                );
        } else {
            Mail::to($this->argument('email'))->send($email);
        }
    }
}
```

Now your artisan command are ready to be test.

### Test Sending E-mail

The first test is to send without queue:

```bash
php artisan email:test your@email.com 
```

You should receive the e-mail almost immediately.

Next, sending out e-mail to using queue. 

> Please make sure you have queue running - either using Horizon or run the **queue:work** command.

```bash
php artisan email:test your@email.com --queue=mail
```

From queue, it might delayed a little bit, depends on your queue processing.

## Summary

With this approach, you can test the mail configuration even in production. 

You don't have to go through the application entire process to test the e-mail configuration.

Another note, we can confirm easily with operation / support team in case they saying e-mail didn't get send to users, by testing first the connectivity to the SMTP server.

This helped reduced time to debug the SMTP connectivity.

## Credits

Photo by <a href="https://unsplash.com/@joannakosinska?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Joanna Kosinska</a> on <a href="https://unsplash.com/photos/envelope-paper-lot-uGcDWKN91Fs?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a>