While building server-side Swift code you probably come along the requirement of sending an email to users. Let it be a confirmation, newsletter signup or a notification message. So we need some kind of email sending possibility. There are a lot of different email services to pick from when speaking about server-side development. (I have good experiences with https://github.com/LiveUI/MailCore but there are other options to pick from). But the advantages and disadvantages of different packages will not be further discussed in this article.
This Article can also be read on my personal blog: https://alexsteiner.de/blog/posts/email-content-dsl/
While sending emails it is possible to style them with HTML but also to include a text-based version. This helps email clients to choose what to display to our users.
But how to maintain one single source of message content while supporting HTML and also plain text messages? One solution is building our own simple Swift DSL around the message content, and that’s what we are going to do in the next few paragraphs.
Separation of Concerns
First, we do not want to write the same code for a title or a paragraph for both plain text and HTML over and over again in different email messages. So let’s make that more reusable and create separated components. Then we can reuse these components in different messages.
Paragraph components look like this. Because we use a struct with the auto-generate constructor we can simply create a new object by calling
Heading(title: “Welcome to our service”).
Now we have an example of components and we know how we can compose them.
Let’s create a protocol
In the end, we want an element to not only be able to generate HTML code, but also a plain text version. Currently, we have the
html property that gives us one of two required properties. But we can additionally add a property that gives us the plain text message. The following protocol represents these requirements quite well:
Later we can access the
html property as well as the
plainText property of our content and pass both into the email before sending it successfully.
And this is already the foundation. Now we need our previous create elements to conform to this protocol. So how does the actual implementation of the elements look like?
We can take our previous written
Paragraph components and conform them to the newly introduced protocol.
But what about actions? Here we can see an implementation of a link action. We can see that in the plain text representation an additional text is added. So we can also add custom hints etc. to our plain text or HTML representation.
Combining multiple elements
Most of the time we don’t only have one element at a time in an email but a combination of multiple components that we want to be stacked together. Instead of manually joining all elements as we did previously we create a wrapper structure that does this job for us but also conforms to the
By combining the different components and appending them in the
MailContent list-like structure, we have our content in place. Now we can access both, the HTML as well as the plain text, of such elements.
An example for sending this mail content via the above-mentioned package “MailCore” looks like this. We can also add a helper function to encapsulate the functionality in case we want to switch the underlying library in the future.
This DSL like structure written in Swift is a good start to make email content more abstract and support accessibility for plain text emails. It gives us the flexibilities to add more elements and stack them together to fulfil our needs.
But as usual, it can still be expanded. For example, we could create element groups with specific style attributes like font color, size or weight. Other attributes could be link action styles or custom images as backgrounds. All of this can be added to this base structure.
Also, there are other options to generate HTML and plain text for emails using Leaf as the article by Andy Finnell describes here. But in his example, two separate template files need to be maintained separately.
So what do you think about creating a DSL for email content? Have you ever considered supporting plain text emails and if so, how have you done that? Let me know your thoughts in the comments, on Twitter or via email.