← Other topics

Local email testing in Laravel

Video Notes

When running a Laravel application on a production server, you’ll want it to be configured to use a real world mail server (e.g. MailGun, SendGrid) so that any outgoing emails will end up in your user’s inboxes.

During testing and development, though, you’ll want to “catch” any outgoing emails so that you can confirm everything is working as expected without actually sending real emails.

There are several ways to do this including:

  1. Route all outgoing mail to a log file
  2. Use a local SMTP server like MailHog
  3. Use a development-specific SMTP server provided by a web service like MailTrap
  4. Route all outgoing mail to global to address

This guide will cover details for setting up each of the above options.

Example set up

To begin, we need some code in our application that will send an email. For this simple example, we can set up a route (/test-email) that invoke’s the Mail facade’s raw method:

# file: /routes/web.php
use Illuminate\Support\Facades\Mail;

Route::get('/test-email', function () {
    Mail::raw('This is a test...', function ($message) {
        $message->to('janedoe@gmail.com')->subject('Testing 123...');
    });

    dd('Email sent!');
});

When this route is invoked, it should trigger an email to janedoe@gmail.com. Of course, the goal is to not actually send an email to janedoe@gmail.com but instead capture that email so we can confirm it matches our expectations. Knowing this - before we trigger this route, let’s configure our mail settings...

Log

To capture any outgoing emails in your log file, open your the .env file in the root of your application and set MAIL_MAILER to log.

Once this is done, trigger the above route (/test-email) and then open /storage/logs/laravel.log and you should see the contents of your email:

  • Pros:
    • Free, quick, and easy setup; no additional accounts/services needed
  • Cons:
    • Can be cumbersome to sort through log contents to find emails
    • Does not replicate the inbox experience we’re used to for reading emails

MailTrap

MailTrap is a web service that provides a dummy inbox for capturing outgoing emails. Create a free account at Mailtrap.io.

Within your account, open the Demo inbox and under SMTP Settings > Integrations choose Laravel and it will give you the environment settings you can copy into your .env file:

Example settings:

MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=your-mailtrap-smtp-username
MAIL_PASSWORD=your-mailtrap-smtp-password
MAIL_ENCRYPTION=tls
  • Pros:
    • Replicates the inbox experience we’re used to for reading emails
    • Extra features including API access for testing and collaboration with other developers
  • Cons:
    • Only free for 500 emails/mo - additional requires a subscription

MailHog - Local SMTP server

Like MailTrap, Mailhog provides a dummy inbox for capturing outgoing emails. The difference, however, is you run Mailhog directly on your computer - it’s not an external web service.

If you installed Laravel via Composer you should update your .env file to use these mail settings:

MAIL_MAILER=smtp
MAIL_HOST=0.0.0.0:1025
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

To start the Mailhog server for a Composer-built Laravel application, run the command mailhog.

If you’re running Laravel via Sail/Docker you should update your .env file to use these mail settings:

MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

When using Laravel Sail, Mailhog is automatically running by default, so no additional commands are needed.

Regardless of whether you’re running Laravel via Composer or Sail, you can access the Mailhog interface via http://localhost:8025.

  • Pros:
    • Free
    • Replicates the inbox experience we’re used to for reading emails
  • Cons:
    • If you’re not using Laravel Sail you have to remember to start the MailHog server

Global to address

Finally, you can inject some code into your AppServiceProvider that will make it so that any outgoing email is routed to a specific email address when your application is running in a local/development environment:

# /app/Providers/AppServiceProvider.php

use Illuminate\Support\Facades\Mail;

public function boot()
{
    if ($this->app->environment('local')) {
        Mail::alwaysTo('mail@codewithsusan.com');
    }
}
  • Pros:
    • Avoids the need for a development-specific SMTP server like MailHog or MailTrap - you can use the same SMTP server you’re using on production.
  • Cons:
    • Can’t confirm that emails are being sent to the correct recipient like you can with one of the other options described above.
If this info helped you out, toss a coin in the tip jar?
← Other topics