FrankMawn's avatar

FrankMawn wrote a comment+100 XP

3mos ago

I love how you made it all opt-in and supported previous ways of doing things. Really nice way to onboard existing projects on v4 and please everybody. Good job!

FrankMawn's avatar

FrankMawn liked a comment+100 XP

6mos ago

You’re right—Laravel's built-in Mail::fake() and Notification::fake() only let you make assertions about the recipients, subjects, mailable classes, etc., but not about the low-level headers on the underlying Swift or Symfony message.

To test that custom headers are actually set on your outgoing mail, you need to avoid faking notifications or mail, and instead use a custom mail transport or mailbox that captures the built Symfony\Component\Mime\Email or, in older Laravel versions, the Swift_Message.

Here’s a practical approach for Laravel 9+, which uses Symfony Mailer:

1. Use assertSent with a callback and tap into the message

If your Notifiable uses the toMail method and in it adds headers via the withSymfonyMessage, you can use Mail::assertSent() with a callback to inspect the message:

Mail::assertSent(YourMailable::class, function ($mail) {
    $headers = null;

    $mail->withSymfonyMessage(function (\Symfony\Component\Mime\Email $message) use (&$headers) {
        // Access headers
        $headers = $message->getHeaders();
    });

    // Now you can check your header
    return $headers && $headers->has('Your-Header-Name') &&
           $headers->get('Your-Header-Name')->getBody() === 'your-value';
});

But: This works only if your mailable exposes the headers via the withSymfonyMessage tap. The assertion is against the mailable object, not the real sent message.

2. (Recommended) Use a Custom Transport That Captures Messages

Instead of faking mail, configure a custom Symfony Transport that keeps the messages in memory for assertions:

namespace Tests;

use Illuminate\Support\Facades\Mail;
use Symfony\Component\Mailer\Transport\NullTransport;
use Symfony\Component\Mime\Email;

class CaptureTransport extends NullTransport
{
    public $messages = [];

    public function send(\Symfony\Component\Mime\RawMessage $message, ?\Symfony\Component\Mailer\Envelope $envelope = null): void
    {
        parent::send($message, $envelope);
        $this->messages[] = $message;
    }
}

Usage in your test:

public function test_email_has_custom_header()
{
    $transport = new \Tests\CaptureTransport();
    Mail::mailer()->setSymfonyTransport($transport);

    // Trigger notification/mailable
    Notification::route('mail', '[email protected]')->notify(new YourNotification);

    /** @var Symfony\Component\Mime\Email $message */
    $message = $transport->messages[0];

    $this->assertTrue(
        $message->getHeaders()->has('Your-Header-Name'),
        'Custom header not found'
    );

    $this->assertEquals(
        'value-you-set',
        $message->getHeaders()->get('Your-Header-Name')->getBody()
    );
}

Notes

  • If you are using older Laravel versions or SwiftMailer, the approach is similar but you'd need to access the Swift_Message object.
  • This pattern lets you test the actual built message, not just the mailable logic.

References:


Summary:

  • For simple cases, use Mail::assertSent() and inspect the headers via the mailable.
  • For certainty, use a custom in-memory transport to capture the full message and assert on the actual headers as the message is delivered.

Let me know if you want a SwiftMailer (Laravel 8.x and below) example!

FrankMawn's avatar

FrankMawn wrote a reply+100 XP

6mos ago

Went with Lary's recommended approach of using a custom Transport driver and was able to successfully do assertions on the mail message headers.

Note that his provided code had a few issues like extending a final class and some method signature errors but nothing that couldn't be fixed.

Thanks LARY.

FrankMawn's avatar

FrankMawn started a new conversation+100 XP

6mos ago

Laravel docs provides a way to add custom email header.

Does anyone know how to assert that the header was included when sending the mail message? I've tried everything (Notification fake, Mail fake) and can't seem to be able to hook into the mail building process to do the assertion on the header.