DEV Community

Cover image for Modernizing Emails: Innovations for Efficient Handling in Distributed Systems
Kristijan Kanalaš
Kristijan Kanalaš

Posted on

Modernizing Emails: Innovations for Efficient Handling in Distributed Systems

Since the beginning of digital businesses, one of the main channels of communication between the business and a client was, and still is, email. Email is a technology that is over 50 years old, and that's one of the reasons for the wide variety of mail clients that render HTML differently from each other — Outlook, I'm looking at you here 👀

Aside from that problem, there is one more: how do we handle sending emails in big distributed systems?!

So... Here is how we modernized emails

Architecture

As is customary nowadays for distributed systems, especially for microservices, we are using a message broker (in our case, RabbitMQ). The message broker handles the communication between multiple applications that want to send an email and an email service that is responsible for rendering and scheduling the email. Here is an example of a message that is being passed through the message broker:

{
    "toEmail": "to@example.com",
    "subject": "Test Subject",
    "templateName": "test",
    "templateData": {
        "name": "test"
    },
    "priority": 200,
    "attachments": [
        {
            "path": "/test/path/file.pdf",
            "filename": "original_filename.pdf"
        },
        {
            "path": "/test/path/file2.pdf"
        }
    ],
    "fromEmail": "from@example.com",
    "fromName": "From Name",
    "replyToName": "Reply-to Name",
    "replyToEmail": "replyto@example.com",
    "toName": "To Name",
    "cc": [
        "cc1@example.com",
        "cc2@example.com"
    ],
    "bcc": [
        "bcc1@example.com",
        "bcc2@example.com"
    ],
    "headers": {
        "X-TEST-HEADER": "Test Value"
    },
   "locale": "en",
   "transportType": "external"
}
Enter fullscreen mode Exit fullscreen mode

To enable rapid integration and keep the above message standardized between applications we made an SDK that contains configuration and DTOs.

Aside from the email properties you likely recognized in the message, you can see emailTemplate and emailData. These two properties allow us to control which template in the email service will be rendered and with what data it will be rendered.

The email service is built with Symfony and its templating engine, Twig. Templates are written in MJML markup, an email framework that helps us address the first problem we mentioned. Twig allows us to pass the data to the MJML template without breaking the MJML structure. After the data is rendered, we send the result to a small MJML service that converts the MJML markup to HTML. Here is an example of a template:

{% extends 'mail/layout/main.mjml.twig' %}

{% block header %}
    {% include "mail/common/header.mjml.twig" %}
{% endblock %}

{% block content %}
    <mj-section>
        <mj-column>
            <mj-text font-weight="300" font-size="24px">
                {% if name is defined %}
                    {{ 'greeting'|trans }} {{ name }}
                {% endif %}
            </mj-text>

            <mj-spacer height="16px" />

            <mj-text font-weight="700" font-size="24px">
                {{ 'intro'|trans }}
            </mj-text>
        </mj-column>
    </mj-section>

    <!-- Main text -->
    <mj-section>
        <mj-column>
            <mj-text>
                {{ 'dataLabel'|trans }} <strong>{{ data }}</strong>
            </mj-text>
            <mj-text>

            </mj-text>
        </mj-column>
    </mj-section>
{% endblock %}

{% block contact %}
    {% include "mail/common/contact.mjml.twig" %}
{% endblock %}

{% block footer %}
    {% include "mail/common/footer.mjml.twig" %}
{% endblock %}
Enter fullscreen mode Exit fullscreen mode

We extend a layout that has defined blocks and fill those blocks with either common reusable parts or new type of content.

After the email is rendered, all that is left is to send it to a transport system, and voilà, we have an email that is beautifully rendered in most common email clients.

Conclusion

Five years ago, we were constantly struggling with synchronizing our layouts across multiple applications, styling emails, and dealing with them randomly breaking in different email clients. But having had this system in place for the last five years, creating emails has become not only manageable but actually kind of fun. We've turned a major headache into a streamlined process, and it's rewarding to see our emails looking great in every inbox — even Outlook 😄

If you'd like to support me writing feel free to buy me a cup of coffee.

BuyMeCoffee

Top comments (0)