How to filter outgoing emails in Laravel

Hello Geek, In this tutorial, I’ll show you how to use event listeners to prevent outgoing emails from being sent.

Laravel provides excellent email support. It also has a very useful hidden feature that allows you to pause the sending of an email notification. I needed this because I didn’t want to send emails to e-mail addresses from a specific domain.

Register the event listener

Laravel dispatches the MessageSending event to your application whenever it sends an email. If this event has listeners, Laravel goes through each listener before sending the email. If one of the listeners returns false, the email will be terminated. This is extremely useful and modular because you do not need to add logic to each mailable you send.

The first step is to configure our new FilterOutgoingEmailsListener to listen for the event. This is possible in the EventServiceProvider:

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

Create an Event Listener to filter outgoing emails

Then, create the FilterOutgoingEmailsListener event listener, which listens for the MessageSending event and returns false if the e-mail should not be sent. If the email should be sent, you should return null (or nothing).

Your event listener could look 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...
    }
}

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,
    ],
]

All the best nerd!

Leave a Reply