DEV Community

Cover image for Step-by-Step Guide to Sending Emails in Laravel Using Multiple SMTP Servers
Shahrukh A. Khan
Shahrukh A. Khan

Posted on • Updated on

Step-by-Step Guide to Sending Emails in Laravel Using Multiple SMTP Servers

Sending emails is a crucial feature in many web applications, from user notifications to marketing campaigns. In Laravel, a popular PHP framework, configuring email delivery is straightforward. However, ensuring reliable email delivery often requires the use of multiple SMTP servers. By setting up multiple SMTP servers, you can create a fallback mechanism that enhances the reliability and efficiency of your email delivery system.

In this article, we will explore the process of configuring Laravel to send emails using multiple SMTP servers. Whether you're dealing with high-volume email campaigns or ensuring redundancy for mission-critical notifications, mastering this setup will help you maintain seamless communication with your users. We'll walk you through the necessary steps, offering tips and best practices along the way. Let's dive in and make your Laravel email system robust and dependable!

First we need to create config option inside config/mail.php inside mailer array there is a default smtp array like below

        'smtp' => [
            'transport' => 'smtp',
            'url' => env('MAIL_URL'),
            'host' => env('MAIL_HOST', '127.0.0.1'),
            'port' => env('MAIL_PORT', 2525),
            'encryption' => env('MAIL_ENCRYPTION', 'tls'),
            'username' => env('MAIL_USERNAME'),
            'password' => env('MAIL_PASSWORD'),
            'timeout' => null,
            'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url(env('APP_URL', 'http://localhost'), PHP_URL_HOST)),
        ],
Enter fullscreen mode Exit fullscreen mode

so we can create similar array with only required field env variables and we wil name it as backup_smtp

        'backup_smtp' => [
            'transport' => 'smtp',
            'host' => env('MAIL_BACKUP_HOST', '127.0.0.1'),
            'port' => env('MAIL_BACKUP_PORT', 2525),
            'encryption' => env('MAIL_BACKUP_ENCRYPTION', 'tls'),
            'username' => env('MAIL_BACKUP_USERNAME'),
            'password' => env('MAIL_BACKUP_PASSWORD'),
        ],
Enter fullscreen mode Exit fullscreen mode

Than we will update our .env files with real SMTP server settings like below

Default SMTP Server

MAIL_HOST=mail.example.com
MAIL_PORT=587
MAIL_USERNAME=primary@example.com
MAIL_PASSWORD=YOUR_SUPER_SECURE_PASSWORD
MAIL_ENCRYPTION=tls
Enter fullscreen mode Exit fullscreen mode

Backup SMTP Server

MAIL_BACKUP_HOST=mail.backup-server.com
MAIL_BACKUP_PORT=587
MAIL_BACKUP_USERNAME=backup@email.com
MAIL_BACKUP_PASSWORD=YOUR_SUPER_SECURE_PASSWORD
MAIL_BACKUP_ENCRYPTION=tls
Enter fullscreen mode Exit fullscreen mode

Until now we have created our Main SMTP Server and Backup STMP Server its time to configure our application to send email with the mail service for this we need to create an abstract class from the command line.

php artisan make:class Services/MailService
Enter fullscreen mode Exit fullscreen mode

Above command will create a MailService class inside app/Service/MailService.php

The next step to create a public function with sendMail() mail which will require 2 arguments the first argument will be mailable so we can use different mailable classes from laravel Mail and the second argument will be the recipient to whom we are sending email to.

MailService.php

<?php

namespace App\Services;

use Exception;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;

class MailService
{
    public function sendEmail($mailable, $recipient)
    {
        try {
            // Primary SMTP Server
            Mail::mailer('smtp')
                ->to($recipient)
                ->send($mailable);

            Log::info("Email sent with Primary SMTP Server.");
        } catch (Exception $e) {
            Log::error("Primary SMTP Server failed to send email" . $e->getMessage());
            try {
                // Primary SMTP Server
                Mail::mailer('backup_smtp')
                    ->to($recipient)
                    ->send($mailable);

                Log::info("Email sent with Backup SMTP Server.");
            } catch (Exception $e) {
                Log::error("Backup SMTP Server failed to send email" . $e->getMessage());
                Log::error("Both SMTP Server failed to send email" . $e->getMessage());
            }
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

To connect this MailService class with our application we will create MailServiceProvider to make things easier and scalable so we will create provider via artisan command as below.

php artisan make:provider MailServiceProvider
Enter fullscreen mode Exit fullscreen mode

Which will be created inside app/Providers/MailServiceProvider.php and we will register our MailService class within laravel container but we do not want this to boot every time.

<?php

namespace App\Providers;

use App\Services\MailService;
use Illuminate\Support\ServiceProvider;

class MailServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     */
    public function register(): void
    {
        $this->app->singleton(MailService::class, function($app){
            return new MailService();
        });
    }

    /**
     * Bootstrap services.
     */
    public function boot(): void
    {
        //
    }
}
Enter fullscreen mode Exit fullscreen mode

Now we'll create a mailable with markdown to send email for this we need to use an artisan command as below since this tutorial is dedicated to enhance the functionality for SMTP I will not be covering mailable here but to sake of this tutorial we will create mailable and controller to send email via artisan command

php artisan make:mail SendEmail --markdown=emails.send-email
Enter fullscreen mode Exit fullscreen mode

Above artisan command will create a mailable inside app/Mail directory as below.

<?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 SendEmail extends Mailable
{
    use Queueable, SerializesModels;

    public $mailData;

    /**
     * Create a new message instance.
     */
    public function __construct($mailData)
    {
        $this->mailData = $mailData;
    }

    /**
     * Get the message envelope.
     */
    public function envelope(): Envelope
    {
        return new Envelope(
            subject: 'Send Email',
        );
    }

    /**
     * Get the message content definition.
     */
    public function content(): Content
    {
        return new Content(
            markdown: 'emails.send-email',
            with: [
                'mailData' => $this->mailData
            ],
        );
    }
}

Enter fullscreen mode Exit fullscreen mode

We can send email in different ways within laravel i.e. Observer or Jobs but to keep things simple we will create controller via artisan command for this tutorial and we will use a protected variable and construct function to load our MailService class when it is being called and I am assuming you are aware of how to create views and validate the post request in laravel.

php artisan make:controller EmailController
Enter fullscreen mode Exit fullscreen mode
<?php

namespace App\Http\Controllers;

use App\Mail\SendEmail;
use App\Services\MailService;
use Exception;
use Illuminate\Http\Request;

class EmailController extends Controller
{
    protected $mailService;

    public function __construct(MailService $mailService)
    {
        $this->mailService = $mailService;
    }

    public function myForm()
    {
        return view('my-form');
    }

    public function myFormPost(Request $request)
    {
        // validate the request

        $emailData = [
            'name' => $request->name,
            'email' => $request->email,
        ];

        $mailable = new SendEmail($emailData);

        try{
            $this->mailService->sendEmail($mailable, $emailData['email']);

            return response()->json(['message' => 'Email has been sent']);
        }catch(Exception $e){
            return response()->json(['message' => $e->getMessage()]);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

For this tutorial we have created a minimal form fields just name and email.

<form action="{{ route('post.form') }}" method="POST">
    @csrf
    <input type="text" name="name">
    <input type="email" name="email">

    <input type="submit" value="Send Email">
</form>
Enter fullscreen mode Exit fullscreen mode

Now will create routes inside web.php to send emails in laravel using multiple SMTP Servers.

Route::get('/send', [EmailController::class, 'myForm'])->name('post.form');
Route::post('/send', [EmailController::class, 'myFormPost']);
Enter fullscreen mode Exit fullscreen mode

It's time to go on the browser and send emails using our codes which we have done so far so open up your browser and test route /send in my case.

http://laravel.test/send
Enter fullscreen mode Exit fullscreen mode

If everything works you should be able to see in browser after filling out the form and click send button you should see as below.

{"message":"Email has been sent"}
Enter fullscreen mode Exit fullscreen mode

Since we are logging messages inside laravel.log with Log::info(); and Log::error(); inside our MailService class we should also see the following message if the mail sent from Primary SMTP server.

local.INFO: Email sent with Primary SMTP Server.  
Enter fullscreen mode Exit fullscreen mode

Once everything works as expected we will change the password for our primary SMTP server email to check if the email is being sent from backup SMTP server.

local.ERROR: Primary SMTP Server failed to send email (along with actual message)
local.INFO: Email sent with Backup SMTP Server
Enter fullscreen mode Exit fullscreen mode

Now we can make sure if the email failed for any reason from primary SMTP server it will be send via backup SMTP server but if the backup SMTP server couldn't send email user/admin will not receive an email.

We hope you enjoyed this guide and learned something new about sending emails in Laravel using multiple SMTP servers. If you found this article helpful, feel free to follow us on X, Instagram.

This blog post was written by the awesome team at diligentcreators.com.

Top comments (0)