Redirecting Test Emails Safely in Laravel

It's a rite of passage which will happen to most devs at one point or another. You're working on a system, there's some email-related functionality, and suddenly you're getting questions from a user about a weird-looking email they just got from your system. Oops! A cold sweat breaks out as you realise that testing real-world email paths from non-production systems is a high-risk activity and start to frantically clear any email queues you can.

This type of mistake happens more often than you'd think. A misconfigured .env, an over-eager tester using real-world data, or a "just-one-last-check" test that quietly emails a real customer.

Fortunately, when we work with Laravel, there's a really nice and simple safety net to protect us from ourselves in these situations - Mail::alwaysTo().

What it does

When Mail::alwaysTo($address) is set in a service provider, it make sure that all mails get sent to our designated address.

// AppServiceProvider
use Illuminate\Support\Facades\Mail;

...

public function boot(): void
{
    if ($this->app->environment('local')) {
        Mail::alwaysTo('my_test_address@example.com');
    }
}

How does it work? What about cc?

Internally when the Mail facade goes to send a mail, if alwaysTo has been used to set an address, then our app will set the To address and ensure the cc and bcc addresses are blanked.

// framework/src/Illuminate/Mail/Mailer.php

// If a global "to" address has been set, we will set that address on the mail
// message. This is primarily useful during local development in which each
// message should be delivered into a single mail address for inspection.
if (isset($this->to['address'])) {
    $this->setGlobalToAndRemoveCcAndBcc($message);
}

...

protected function setGlobalToAndRemoveCcAndBcc($message)
{
    $message->forgetTo();

    $message->to($this->to['address'], $this->to['name'], true);

    $message->forgetCc();
    $message->forgetBcc();
}

Flexible configuration

In the example above, the alwaysTo is always set on the local environment. But perhaps we want it to be set on all non-production environments. Or we want it set by default in all developer environments, with some devs being able to override it when working on email functionality. Following Laravel convention, we can manage this through our env and config files!

In our standard .env file, we add a variable like this:

MAIL_OVERRIDE_TO=always_to_me@example.com

In our config/mail.php, use this value where set:

// config/mail.php

// Used to restrict sending to one address in a test-live environment
'override_to' => env('MAIL_OVERRIDE_TO'),

Then in our AppServiceProvider's boot method:

// Apply local override if env var has been set
if (config('mail.override_to')) {
    Mail::alwaysTo(config('mail.override_to'));
}

This will mean that anyone using that stock env file has the alwaysTo mail behaviour enabled. For live environments, and for devs who need to test "live" mail functionality, the value can be blanked, and real emails will be sent.

Set it, then forget it!

Software is full of sharp edges, and most of them only hurt once. This is one of those small tools that quietly removes one of those edges! Set it up, forget it, and let your future self stay blissfully unaware of the crisis that never happened.


IPC Munich 2025

IPC Berlin Speaker

In October 2025, I'll be speaking at the International PHP Conference in Munich. I'll be talking about Modern PHP Features You’re Probably Not Using (But Should Be). Expect real-world examples, practical takeaways, and a deep dive into cleaning your code while making your life easier!

Get your ticket now (use ipcmuc-paul for 10% off) and I'll see you there!


Share This Article

Related Articles


More