I was not able to fathom this, so for each mail sent, I created a record in an email_sends table and created a UUID as the primary key.
Then attach this as a bespoke header to the outgoing email with;
$this->withSymfonyMessage(function ($message) use ($emailSend) {
$message->getHeaders()->addTextHeader('X-CVE-ESID', $emailSend->id);
$message->getHeaders()->addTextHeader('X-CVE-PURP', $emailSend->purpose);
});
and then when the SNS message comes in, retrieve the X-CVE-ESID back from the payload and see if it exists in the database
<?php
namespace App\Http\Controllers\Webhooks;
use App\Http\Controllers\Controller;
use App\Models\EmailSend;
use App\Services\Emails\EmailVerificationService;
use Aws\Sns\Exception\InvalidSnsMessageException;
use Aws\Sns\Message;
use Aws\Sns\MessageValidator;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class SnsController extends Controller
{
private $message;
public function receive(Request $request)
{
$message = Message::fromRawPostData();
$validator = new MessageValidator();
try {
$validator->validate($message);
} catch (InvalidSnsMessageException $e) {
Log::error('SNS Message Validation Error: ' . $e->getMessage());
}
$this->message = json_decode($message->offsetGet('Message'), false);
if(!$this->message) {
Log::error('Unexpected SNS message type');
Log::info($message->toArray());
abort(500);
}
$handler = 'handle' . optional($this->message)->eventType ?? 'none';
try {
$emailsend = EmailSend::where('id', $this->getMessageEsid())->first();
} catch (\Throwable $th) {
// email is not tracked, or does not contain the right headers, ignore.
return;
}
if(method_exists($this, $handler)) {
$this->$handler($emailsend);
} else {
Log::error('Unexpected SNS topic received');
Log::info(json_encode($this->message));
}
}
private function handleSend($emailsend)
{
$emailsend->update(['send_at' => Carbon::parse($this->message->mail->timestamp)]);
}
private function handleDelivery($emailsend)
{
$emailsend->update(['delivered_at' => Carbon::parse($this->message->delivery->timestamp)]);
}
private function handleOpen($emailsend)
{
$emailsend->update(['opened_at' => Carbon::parse($this->message->open->timestamp)]);
}
private function handleBounce($emailsend)
{
$emailsend->update([
'bounce_at' => Carbon::parse($this->message->bounce->timestamp),
'bounce_type' => $this->message->bounce->bounceType . ':' . $this->message->bounce->bounceSubType,
]);
}
private function handleComplaint($emailsend)
{
$emailsend->update([
'bounce_at' => Carbon::parse($this->message->complaint->timestamp),
'bounce_type' => $this->message->complaint->complaintSubType ?? 'Complaint:' . $this->message->complaint->complaintFeedbackType ?? '',
]);
}
private function getMessageEsid()
{
return $this->findHeader('X-CVE-ESID');
}
private function findHeader($header)
{
$headers = collect($this->message->mail->headers);
return $headers->where('name',$header)->first()->value;
}
}