Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

threelyons's avatar

How to get the email response headers after sending?

I am trying to get the message ID when sent via SNS in Laravel 9, but so far I can't seem to figure it out.

I need to store the message ID after it has been sent from the response received after sending via SES. But whatever I have tried has failed.

I read an article discussing how to set up email tracking with AWS SEs and SNS. And I have managed to set up eh AWS side, as well as subscribed to the SNS topic. Sending emails is not a problem either. I just can't seem to grab the header provided by AWS when I send an email, which will later be used to map against the SNS notification sent with status updates.

Any help would be greatly appreciated. I am using Laravel 9. and the below code doesn't work.

$headers = "";
    
    Mail::send(new SendEmail($data), ['data' => $data], function ($message) use (&$headers, $request) {
        $message->to($request->to_email_address)->subject($request->subject);
        $headers = $message->getHeaders();
    });        
    $message_id = $headers->get('X-SES-Message-ID')->getValue();

    Log::info($message_id);
0 likes
2 replies
Snapey's avatar
Snapey
Best Answer
Level 122

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;
    }
}

1 like
threelyons's avatar

@Snapey Excellent, many thanks. Yes, I did have a table for all sent emails. But I didn't realise I could read my own custom headers in the SNS notifications. Thats all perfect, up and running now.

Many thanks

Please or to participate in this conversation.