Tips to send great e-mails with Symfony
I migrated my posts to my own blog because Medium is becoming less and less comfortable for readers (paywalls, impossibility to highlight the code, etc.). To read this article in a nicer and privacy friendly context, read it on my personal blog and follow me on Twitter to get notified!
https://titouangalopin.com/tips-to-send-great-e-mails-with-symfony/
Since it’s creation during the 60’s, e-mails have been one of the most used and most important feature of Internet. E-mails are a decentralized and reliable technology that is compatible with pretty much every device you can think of.
Thus, sending great emails is critical for any startup: it’s a way to reach the users where there are available, to notify them and get them to come back on your product. Transactional and marketing e-mails are the basis on which many startups become successful.
Sending great e-mails, though, is not as easy as it sounds. There are many challenges to create beautiful e-mails which will actually reach their recipient and will be compatible with all their devices.
Here are some tips on how to send great emails the proper way with Symfony and a few other tools.
Do not send your e-mails in your requests
As I said, e-mails are a wonderful piece of technology. However, components of it can be a bit more unstable. By using a decentralized network of servers, one can never be sure an e-mail will be easily and quickly sent.
Sending an e-mail in the process of a request is therefore a really bad idea: it can be slow, it is prone to failures, and if there is a failure, it can’t be easily retried.
Instead, it is recommended to use a queuing system, like RabbitMQ. With such systems, you will be able to quickly add a “job” in the queue to send the mail, and a background worker you developed will then process the job, sending the e-mail. If a failure occurs, the job can be put again in the queue to be retried later. This mechanism is essential to send mails in a reliable and scalable way.
Fortunately, Symfony integrates really well with such systems. Besides the official Symfony Messenger component, which is still a bit experimental until Symfony 4.2 in November 2018, there are several libraries able to handle these jobs for you, like php-enqueue or RabbitMQBundle. Don’t hesitate to use them!
SPAMs
The huge success of e-mail is also its main threat. By being so widely used, it is the perfect vector to propagate ads, false information and viruses. SPAMs are everywhere, from small to big email inboxes.
To counter this, e-mail providers are becoming increasingly strict and careful about what e-mails they show to their users. This means that being able to send e-mails which will actually reach their recipients and not their SPAM box is becoming more and more difficult.
Nowadays, using your own SMTP server is becoming extremely hard: from the trust in the IP address to the headers required and the signatures you need to add, ensuring your e-mails will reach your users will require a lot of time you probably don’t have.
If you use something like SensioCloud, this problem is handled for you by the platform. In other cases, remote SMTP services like Sendgrid, Mailchimp or Mailjet are useful. Many providers exist in this market, but I tend to prefer Sendgrid for its simplicity and reliability.
Using Sendgrid or any similar product is as simple as using their SMTP server instead of yours in your Swiftmailer configuration. They will handle for you all the difficulties of sending e-mails, making sure these e-mails actually reach their recipients. Moreover, most of these services offer a free amount of mails you can send (100/day for Sendgrid). Use it!
Abstract the complexity of compatibility
There are thousands of e-mail clients on many various platforms. All of these clients have different levels of compatibility over what can be done in an e-mail. Creating HTML e-mails that are compatible with every single one of them can be very challenging. This is why tools like MJML were created.
MJML provides an XML format which lets you create responsive e-mails using simple XML tags for generic component. Once created, your e-mails can then be dumped into real HTML that you will be able to send. You can have a look at their live editor to see how it looks.
I personally use MJML in combination with Twig: I write MJML files with Twig tags in it. Once my MJML+Twig files are ready, I use the Javascript library to dump them in HTML: the library ignores the Twig tags, which are directly copied into the HTML files, creating perfectly compatible Twig files for usage in my Symfony application.
Using this technique, I am able to write great HTML e-mails much faster:
<mjml>
<mj-body>
<mj-container background-color="#EDEDEE">
<mj-section padding-bottom="20" padding-top="20">
<mj-column>
<mj-image src="https://example.com/logo.png" alt="" align="center" border="none" width="150" padding-left="0" padding-right="0" padding-bottom="10" padding-top="10">
</mj-image>
</mj-column>
</mj-section>
<mj-section background-color="#ffffff" padding-bottom="30" padding-top="30" border-top="10px solid #196162">
<mj-column>
<mj-text align="center" color="#196162" font-size="30px" font-family="Montserrat, Arial, Helvetica, sans-serif" font-weight="bold">
Welcome aboard!
</mj-text>
</mj-column>
</mj-section>
<mj-section background-color="#ffffff" padding-bottom="0">
<mj-column>
<mj-text align="center" color="#4B4B4B" font-size="20px" font-family="Montserrat, Arial, Helvetica, sans-serif">
You're now a user!
</mj-text>
</mj-column>
</mj-section>
<mj-section background-color="#ffffff" padding-left="40" padding-right="40" padding-bottom="0">
<mj-column>
<mj-button href="{{ app_url }}" background-color="#196162" align="center" color="#ffffff" font-size="22px" font-family="Montserrat, Arial, Helvetica, sans-serif">
Explore the website
</mj-button>
</mj-column>
</mj-section>
<mj-section background-color="#ffffff" padding-top="10" padding-left="40" padding-right="40" padding-bottom="40">
<mj-column>
<mj-text align="center" color="#4B4B4B" font-size="16px" font-family="Montserrat, Arial, Helvetica, sans-serif">
Questions ?<br />
We're here to help:
<a href="mailto:{{ mail_contact }}" color="#db910e">{{ mail_contact }}</a>!
</mj-text>
</mj-column>
</mj-section>
</mj-container>
</mj-body>
</mjml>
Happy e-mails sending!
Have some other tips to share? Leave a comment to spread the word!