Scroll down to the script below, click on any sentence (including terminal blocks!) to jump to that spot in the video!
I want to propose two cool ideas.
First, while we're developing, if we decide to use Mailtrap, great: all of our emails will go there. But if we decide that we want to use SendGrid to send real emails while developing... it's a little trickier. For example, whenever you register, you would need to use a real email address. Otherwise, the email would never make it to your inbox.
So here's idea number 1: what if, in the
dev environment only, we globally
override the "to" of every email and send to ourselves. So even if we
[email protected] - the email would actually be delivered
to our real address:
[email protected] for me. That would be cool!
My second idea is similar: instead of manually setting the
on every email object... what if we hook into mailer and set this globally.
That's less duplication and more consistency.
The way to accomplish both of these is by leveraging an event. Whenever an
email is sent through Mailer, internally, it dispatches one event called
MessageEvent. Mailer itself comes with a couple of classes that can
"listen" to this event. The most interesting one is called
I'll hit Shift+Shift and look for
EnvelopeListener so we can see inside. Start
by looking for
getSubscribedEvents(). Yep! This is listening on
MessageEvent. Here's the idea: if you used this class, you could instantiate
it and pass a custom sender or a custom array of recipients. Then, whenever an
email is sent, the
onMessage() method would be called and it would override that
stuff on the email.
I love it! Even though this class lives inside Mailer, Symfony doesn't activate it by default: it's not currently being used. In Symfony 4.4, some new config options were been added so you can activate & configure it easily:
# config/packages/mailer.yaml # or config/packages/dev/mailer.yaml for only the dev environment framework: mailer: envelope: sender: '[email protected]' recipients: ['[email protected]']
But in Symfony 4.3, if we want to use this class, we need to activate it manually... which is kinda fun anyways.
So here's the plan: to start, in the development environment only, I want all
emails to actually be sent to
[email protected], regardless
to() address on the email.
To do this, in
.env, let's create a brand new, shiny environment variable:
DEV_MAIL_RECIPIENT set to, how about,
[email protected]. That's not a real
email, because each developer should need to copy this variable, open
.env.local file, and customize it to whatever they want.
Next, we need to register
EnvelopeListener as a service... but only in the
dev environment: I don't want to change the recipients on production. To do
that, in the
config/ directory, create a new file called
Thanks to that
_dev part, this will only be loaded in the
dev environment. At
the top, start with the same
_defaults code that we have on top of our main
services:, then the magic
_defaults: to set up some default
options that we want to apply to every service registered in this file. The
default config we want is
autowire: true and
Now, let's register
EnvelopeListener as a service. Copy its namespace, paste,
\ then go copy the class name and put that here too. For arguments, the
class has two:
$sender and an array of
$recipients. We'll focus on setting
the "sender" globally in a few minutes... but for right now, I don't want to
use that feature... so we can set the argument to
null. Under arguments, use
- null for sender and, for recipients,
-  with
one email inside. To reference the environment variable we created, say
then copy the variable name -
DEV_MAIL_RECIPIENT - and paste it in the middle.
That should be it! This will register the service and, thanks to
Symfony will configure it as an event subscriber.
Testing time! Move over, refresh and... ah! I have a typo! The key should be
_defaults with an "s". Try it again. This time register with a fake email:
[email protected], any password, agree to the terms and register!
Because our app is configured to use SendGrid... that should have sent a real email. Check the inbox - we have a new one! That's the original email from a minute ago on top... and here's the new one.
But! This is even cooler. If you were watching really closely, you
may have noticed that, in
EnvelopeListener, what we're setting is something
called "recipients". But when we create an email... we use a method call
It turns out, those are two different concepts. Gasp!
Here's what's going on. Just like how, in the real world, you put a "message"
into an "envelope" and then send it through the real-world mail, an email is
also these same two parts: the message itself and an envelope that goes around
To of an email is what's written on top of the "message". But the
envelope around that message could have a totally different address on it.
That is known as the "recipient". The envelope is how the email is delivered.
And the message is basically what you're looking at inside your inbox.
This... for the most part... is just fun mail trivia. Most of the time, the
"To" and the "recipients" will be the same. And... that's exactly what happens
if you set the
To but don't set the recipients: mailer sets the
recipients for you... to match the
This idea becomes even more important when we talk about setting the
address globally so we don't need to set it on every email. Because... yep,
from is different than "sender". That's next.