Laravel prevent duplicate emails

On a recent project I misread a ticket and understood it as a need to prevent duplicate emails being sent (within a certain amount of time). I’d realized the ticket was calling for something different, but I finished some investigation on what it would take to prevent potentially accidental duplicate sends.

My first thought was to write a plugin for the swift_mailer component, which … I did, but then realized it may be easier to hook in to the event system at the Laravel level (vs down lower in the mailer plugin level).

I ended up adding an event listener in EventServiceProvider.php

protected $listen = [
'Illuminate\Mail\Events\MessageSending' => [
'App\Listeners\PreventDuplicateEmail',
],
];


The PreventDuplicateEmail class

namespace App\Listeners;

use Illuminate\Mail\Events\MessageSending;
use Swift_Message;

class PreventDuplicateEmail
{
static $done = [];

public function handle(MessageSending $event)
{
$message = $event->message;
$hash = $this->hash($message);
$toRecipients = $message->getHeaders()->getAll("to")[0]->getNameAddresses();
foreach($toRecipients as $email=>$name)
{
if(!array_key_exists($email.$hash, self::$done))
{
self::$done[$email.$hash] = time();
}
}
}

public function hash(Swift_Message $message)
{
$subject = $message->getSubject();
$body = $message->getBody();
$from = array_key_first($message->getFrom());
$combined = $subject.$body.$from;
return substr($subject, 0,20).":".substr($from,0,20).":".sha1($combined);
}

}

This isn’t finished – to prevent sending, use a ‘return false;’ in the listener. And determining the window – 5 minutes? 1 hour? – that’d be up to you. You could store everything in a database table and check there as well. Because I’d misread the requirements, I didn’t completely finish this, but hopefully this gets you a bit closer if this is what you were looking for…

Leave a Reply

Your email address will not be published. Required fields are marked *