Transport Config & Mailtrap

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

We've already learned quite a bit about how to customize a specific email... with a lot more coming. But how do we customize how an email is sent. In Symfony, the way that your messages are delivered is called a transport. Go back to your terminal and run:

git status

The Mailer dsn

When we installed the Mailer component, its recipe did a couple of interesting things. First, it created a new file called config/packages/mailer.yaml. Let's open up that up. Wow... as you can see: the mailer system doesn't really have a lot of config. The only thing here is the dsn: a URL that tells Mailer what server or cloud service to use for delivery. This references an environment variable called MAILER_DSN. Hey! That's the error we just saw:

Environment variable not found: "MAILER_DSN".

The recipe also modified the .env file. If you run

git diff .env

Yep! You'll see that it added a section with an example MAILER_DSN.

Configuring MAILER_DSN

Open up .env. And, at the bottom, uncomment that MAILER_DSN line. By default, this tries to send to a local SMTP server... and I definitely do not have one of those running. But... let's try it anyways. Refresh to resubmit the registration form and... boom!

Connection could not be established with host "tcp://localhost:25"

So how are we going to send emails? Because... there are a lot of different options. You could run your own SMTP server... which is not something I recommend... or register with a cloud email sender - like SendGrid - and use your connection details from them for Mailer. Mailer supports a bunch of the most famous cloud providers... as well as any cloud provider that implements SMTP... which is like... all of them. We're going to show how to use SendGrid a bit later.

Why are we not going to use SendGrid right now? Because... when you're developing and debugging your emails, there's a better option. Instead of sending real emails to a real email server, you can send them to a "fake" mailbox.

One of the most famous tools to do this is called MailCatcher. Basically, you download MailCatcher, start it on your machine, and it creates a temporary SMTP server that you can send to. But instead of delivering the messages, it holds onto them and you can view them all in a fake inbox in your browser. MailCatcher is written in Ruby and a similar tool - MailHog - is written in Go. Those are both great options.

Hello Mailtrap

But... to save me the headache of getting those running, I'm going to use a third option called Mailtrap. Head to mailtrap.io. This is basically a "hosted" version of those tools: it gives us a fake SMTP server and fake inbox, but we don't need to install anything. And it has an excellent free plan.

After you register, you'll end up in a spot like this: with a "Demo inbox". Click into that Demo inbox. On the right, you'll see a bunch of information about how to connect to this. At the time of recording, they do have specific instructions for Symfony 4... but these are for using Mailtrap with SwiftMailer, not Symfony Mailer.

No worries, setup is dead simple. The DSN follows a standard structure: username:password@server:port. Copy the username from Mailtrap, paste, add a colon, copy and paste the password, then @ the server - smtp.mailtrap.io - one more colon, and the port. We could use any of these. Try 2525.

Done! If we haven't messed anything up, our email should be delivered to our Mailtrap inbox. Let's try it! Refresh the form submit and... ah! Validation error. The last time we tried this, the email failed to send but the user was saved to the database. Make the email unique by adding a "2". Then click the terms, enter any password and... register!

Ok, no errors! Go check Mailtrap! There it is! It's got the subject, text content, but no HTML content because we haven't set that yet. There are also a couple of other cool debugging features in Mailtrap - we'll talk about some of these soon.

Now that we've got some success, it's time to attack the obvious shortcoming of this email... it's just text! It's not 1995 anymore people, we need to send HTML emails. And Mailer gives us a great way to do this: native integration with Twig. That's next.

Leave a comment!

This tutorial is built on Symfony 4.3, but will work well with Symfony 4.4 or 5.

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.1.3",
        "ext-iconv": "*",
        "aws/aws-sdk-php": "^3.87", // 3.110.11
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "knplabs/knp-markdown-bundle": "^1.7", // 1.7.1
        "knplabs/knp-paginator-bundle": "^2.7", // v2.8.0
        "knplabs/knp-snappy-bundle": "^1.6", // v1.6.0
        "knplabs/knp-time-bundle": "^1.8", // v1.9.1
        "league/flysystem-aws-s3-v3": "^1.0", // 1.0.23
        "league/flysystem-cached-adapter": "^1.0", // 1.0.9
        "league/html-to-markdown": "^4.8", // 4.8.2
        "liip/imagine-bundle": "^2.1", // 2.1.0
        "nexylan/slack-bundle": "^2.1,<2.2.0", // v2.1.0
        "oneup/flysystem-bundle": "^3.0", // 3.1.0
        "php-http/guzzle6-adapter": "^1.1", // v1.1.1
        "sensio/framework-extra-bundle": "^5.1", // v5.4.1
        "stof/doctrine-extensions-bundle": "^1.3", // v1.3.0
        "symfony/asset": "^4.0", // v4.3.4
        "symfony/console": "^4.0", // v4.3.4
        "symfony/flex": "^1.9", // v1.9.10
        "symfony/form": "^4.0", // v4.3.4
        "symfony/framework-bundle": "^4.0", // v4.3.4
        "symfony/mailer": "4.3.*", // v4.3.4
        "symfony/messenger": "4.3.*", // v4.3.4
        "symfony/orm-pack": "^1.0", // v1.0.6
        "symfony/security-bundle": "^4.0", // v4.3.4
        "symfony/sendgrid-mailer": "4.3.*", // v4.3.4
        "symfony/serializer-pack": "^1.0", // v1.0.2
        "symfony/twig-bundle": "^4.0", // v4.3.4
        "symfony/twig-pack": "^1.0", // v1.0.0
        "symfony/validator": "^4.0", // v4.3.4
        "symfony/web-server-bundle": "^4.0", // v4.3.4
        "symfony/webpack-encore-bundle": "^1.4", // v1.6.2
        "symfony/yaml": "^4.0", // v4.3.4
        "twig/cssinliner-extra": "^2.12", // v2.12.0
        "twig/extensions": "^1.5", // v1.5.4
        "twig/inky-extra": "^2.12" // v2.12.0
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.0", // 3.2.2
        "easycorp/easy-log-handler": "^1.0.2", // v1.0.7
        "fzaninotto/faker": "^1.7", // v1.8.0
        "symfony/browser-kit": "4.3.*", // v4.3.5
        "symfony/debug-bundle": "^3.3|^4.0", // v4.3.4
        "symfony/dotenv": "^4.0", // v4.3.4
        "symfony/maker-bundle": "^1.0", // v1.13.0
        "symfony/monolog-bundle": "^3.0", // v3.4.0
        "symfony/phpunit-bridge": "^3.3|^4.0", // v4.3.4
        "symfony/profiler-pack": "^1.0", // v1.0.4
        "symfony/var-dumper": "^3.3|^4.0" // v4.3.4
    }
}