Global Tags and Metadata on Laravel Mailables

Adding site specific tags or meta-data to all mailables

Laravel mailables have a nice interface for consistently structuring an email for any of their supported drivers.

As I'm often working with Mailgun I like Laravels support for tags and metadata which lets you add additional metadata to a message for easier filtering inside mailgun:

//Inside your mailable class
 public function envelope(): Envelope
    {
        return new Envelope(
            subject: 'Testing Tags',
            tags: ['mail-1', 'mail-2'],
            metadata: [
                'type' => 'from-envelope',
            ],
        );
    }

That's great for mail-specific tags, but if you are sharing one sending address between multiple apps and have a lot of mail and notifications it can be handy to tag all messages out of a specific site with a globally added metadata to separate the sending application.

There's no obvious way to do this, but after a bit of source diving into the base Laravel and Symfony classes I've found a reasonable solution:

//In AppServiceProvider boot(), or in a custom service provider
Event::listen(MessageSending::class, function (MessageSending $event) {
    if ($tag = config('mail.tag')) {
        $event->message->getHeaders()->add(new TagHeader($tag));
    }

    if ($metadata = config('mail.metadata')) {
        foreach ($metadata as $key => $value) {
            if ($value) {
                $event->message->getHeaders()->add(new MetadataHeader($key, $value));
            }
        }
    }
});

This hooks into all messages as they are being sent and adds any tags or metadata added inside config/mail.php as a tag string and an array of metadata key/values:

//config.mail.php

    'tag' => 'global-1',
    'metadata' => [
        'site' => env('APP_NAME'),
        'environment' => env('APP_ENV'),
    ],

This will merge with the tags and metadata from the envelope so the finished result gives you this in the final mail headers:

X-Metadata-Environment

local

X-Metadata-Site

(Site Name)

X-Metadata-Type

from-envelope

X-Tag

mail-1

mail-2

global-1

Notes:

  • With Mailgun a single message can only have up to 3 tags, so avoid adding more than two tags in any template if you use this system

  • This same technique can be used to add global SES tags to Laravel mails, but you need to use the metadata method for SES tags.

  • Test before use! Causing an error in the sending event will mean no mails will be able to send!