How to filter outgoing emails in Laravel (2022) | RJS

How to filter outgoing emails in Laravel (2022)

In this tutorial I'll show you how to use event listeners to stop outgoing emails just before they're sent.

Ralph J. Smit Laravel Software Engineer

Laravel has great support for sending emails. It also offers a very useful hidden feature that allows you to stop an email of notification from being sent. I needed this because I wanted to prevent sending emails to a e-mailadresses from a specific domain.

In this tutorial, I'll explain to you how you can stop emails and notifications from being sent.

1. Register the event listener

Whenever Laravel sends an email, it dispatches the MessageSending event to your application. If there are listeners for this event, Laravel goes through each listener before sending the email. If one of the listeners returns false, the email will be stopped in its tracks. This is very useful and modular, because you don't need to add logic to every mailable you are sending.

The first thing you need to do is register our new FilterOutgoingEmailsListener to listen for the event. You can do this in the EventServiceProvider:

use Illuminate\Notifications\Events\NotificationSending;
 
protected $listen = [
MessageSending::class => [
FilterOutgoingEmailsListener::class,
],
]

2. Create an Event Listener to filter outgoing emails

Next, you need to create the FilterOutgoingEmailsListener event listener that listens to the MessageSending event and returns false if the e-mail shouldn't be sent. You should return null (or nothing) if the email should be sent.

You event listener could look something like this:

class FilterOutgoingEmailsListener
{
public function handle(MessageSending $event): null|bool
{
// Get the email address as a string
$email = Arr::first($event->message->getTo())?->getAddress();
 
if ( ! $this->shouldSendEmail($email) ) {
return false;
}
 
return null;
}
 
protected function shouldSendEmail(string $emailAddress): bool
{
// Determine whether the email should be sent...
}
}

3. Bonus: Also filter outgoing Notifications

The above solutions works very well for notifications as well. To filter outgoing notifications, you should update the FilterOutgoingEmailsListener listener as well to listen for notifications.

Your file could look like the example below. The handle() now accepts both types of events, extracts the email address and checks whether the email is allowed.

class FilterOutgoingEmailsListener
{
public function handle(MessageSending|NotificationSending $event): null|bool
{
if ($event instanceof NotificationSending && ! in_array('mail', $event->notification->via($event->notifiable))) {
return null;
}
 
// Get the email address as a string
$email = match($event::class) {
NotificationSending::class => $event->notifiable->routeNotificationFor('mail'),
MessageSending::class => Arr::first($event->message->getTo())?->getAddress()
};
 
if ( ! $this->shouldSendEmail($email) ) {
return false;
}
 
return null;
}
 
protected function shouldSendEmail(string $emailAddress): bool
{
// Determine whether the email should be sent...
}
}

Next, we should also update our EventServiceProvider, so that both events point to the same event listener:

protected $listen = [
MessageSending::class => [
FilterOutgoingEmailsListener::class,
],
NotificationSending::class => [
FilterOutgoingEmailsListener::class,
],
]

Conclusion

As you've seen, it is pretty easy to filter outgoing emails in Laravel. You can use this for many things. For example, I used it to prevent sending emails to specific domains. Another use case would be to only allow sending emails to domain of your company in local and staging environments. In that way you could prevent sending emails to real users during testing 👊

Published by Ralph J. Smit on in Laravel. Last updated on 02 September 2022.


Like what you read?

Get notified when I publish something new, and unsubscribe at any time.