💡 This page contain affiliate links. By making a purchase through them, we may earn a commission at no extra cost to you.
My Approach to Readable CSS in HTML Emails

My Approach to Readable CSS in HTML Emails

Making inline CSS manageable in emails with JavaScript
Ferenc AlmasiLast updated 2021 November 11 • Read time 5 min read
Get your weekly dose of webtips
  • twitter
  • facebook
CSS

Recently, I started working on a password recovery implementation and I was thinking about what would be — if not even the cleanest — but still a good solution to style my email template without having to go mad while reading inline CSS.

See, the problem with HTML emails is that you can’t source out your CSS style declarations, you only have a limited option: exactly one, which is to use inline styles. I wanted to send out the emails through an Express server so it was evident to use JavaScript and hence this article was born.

Before we get into coding, however, It’s important to mention that we have a bunch of user-friendly online tools that have a GUI with which you can create stunning email templates.

For my problem, having it all done in JavaScript seemed to be the optimal and simplest solution. I only needed a single template and also wanted to have full control over everything.


Creating Templates

Starting off, you of course want to have a template. I’ve created a function which exports the following string:

Copied to clipboard! Playground
module.exports = () => `
    <div style="${getStyles(styles.wrapper)}">
        <div style="${getStyles(styles.card)}">
            <h1 style="${getStyles(styles.heading)}">We've received a request to reset your password.</h1>
            <p style="${getStyles(styles.description)}">Your password has been reset...</p>
            <span style="${getStyles(styles.password)}">Your new password</span>
        </div>
        <a href="https://diettime.app/dashboard" target="_blank" style="${getStyles(styles.link)}">Go to Dashboard</a>
    </div>
`;
passwordReset.js

Here you can see that I’ve used a template literal, so I can wrap HTML elements and make them readable. I’ve solved the inline styling problem with a function call. It gets the CSS styles and turns them into inline styling. But what does the function do internally and where do the parameters coming from?


Adding CSS

First I’ve created a container object for storing the CSS styles and created additional objects inside it to define the CSS properties for each element. These are the objects that are passed down into the function call:

Copied to clipboard! Playground
const styles = {
    wrapper: {
        'background': 'linear-gradient(135deg,  #aa00ff 0%,#6a1b9a 100%)',
        'border-radius': '4px',
        'padding': '50px 25px',
        'color': '#FFF',
        'text-align': 'center',
        'max-width': '600px',
        'margin': '20px auto'
    },
    ...
}
passwordReset.js

Each property inside the object is the name of a CSS property associated with its CSS value. This is what we pass into the getStyles function whose sole responsibility is to create the inline CSS styles for it.

So what is the solution? It can actually be done in one single line of code:

Copied to clipboard!
const getStyles = (object) => Object.keys(object).map(key => `${key}:${object[key]}`).join(';');
passwordReset.js

We can loop through the object with Object.keys and map on each value where we concatenate the key with the value using colons. After that, we can join them together with a semicolon.

The same piece of code has other use cases such as generating query strings:

Generating query strings in JavaScript
Looking to improve your skills? Master CSS from start to finish.
Master CSSinfo Remove ads

Adding Localization Support

While at it, while not source out the text itself? That way, we can add localization support in a relatively easy way. All we have to do is pass an object to our function then reference the keys in the template:

Copied to clipboard! Playground
module.exports = i18n => `
    <div style="${getStyles(styles.wrapper)}">
        <div style="${getStyles(styles.card)}">
            <h1 style="${getStyles(styles.heading)}">${i18n.passwordResetTitle}</h1>
            <p style="${getStyles(styles.description)}">${i18n.passwordResetDescription}</p>
            <span style="${getStyles(styles.password)}">${i18n.newPassword}</span>
        </div>
        <a href="https://diettime.app/dashboard" target="_blank" style="${getStyles(styles.link)}">${i18n.passwordResetGoToDashboard}</a>
    </div>
`;
passwordReset.js

Here I added an i18n parameter to the function that holds an object to a couple of keys. For each language, you can create a new file holding the necessary translations. I’ve created a separate folder for them called i18n:

The localization folder structure

And each of them exports an object with the necessary keys:

Copied to clipboard! Playground
module.exports = {
    passwordResetTitle: 'We received a request to reset your password.',
    passwordResetDescription: 'Your password has been successfully reset...',
    ...
}
en.js

The way you would use them is to import the template and one of the localization files, depending on your needs. You can import them based on some variable, for example, a request param, and call the function to generate the template:

Copied to clipboard! Playground
const passwordResetTemplate = require('templates/passwordReset.js');
const i18n = require('../i18n/' + (request.body.locale || 'en'));

// Generate template
passwordResetTemplate(i18n);
index.js

And the end Result?

HTML email formatted with CSS

I’ve used images in my template, but for them to appear, you want to send out the emails through a trusted SMTP server. Otherwise your images not only won’t appear, but more importantly, your emails will land in the spam folder.

It’s also important to mention that you have some limitations when it comes to CSS. Not all styles are supported by email clients. For example: although you see a nice box-shadow applied here, this is the exception. Most of the email clients don’t support it, including Gmail. If you however really insist, you’re better off using images. And since you have more email clients than browsers, making a consistent design for them can be a challenge.

This is why I would advise to only include the most necessary and basic things, such as colors or layout. Everything else should only be a compliment and your emails should look polished even without them.

So how do you actually send out the mails with Express? That deserves its own article which I’m planning to write in the near future, so make sure to follow up. 🍊

Thank you for taking the time to read this article, happy styling!

  • twitter
  • facebook
CSS
Did you find this page helpful?
📚 More Webtips
Frontend Course Dashboard
Master the Art of Frontend
  • check Access 100+ interactive lessons
  • check Unlimited access to hundreds of tutorials
  • check Prepare for technical interviews
Become a Pro

Courses

Recommended

This site uses cookies We use cookies to understand visitors and create a better experience for you. By clicking on "Accept", you accept its use. To find out more, please see our privacy policy.