Skip to content

Email Markup Development in React — 2025

Author's photo
10 min read ·

In this article, I’m sharing my take on the current state of email markup development, along with some awesome tools, frameworks, and resources I’ve come across (and actually used!) while giving our email rendering stack at Prezly a modern makeover.

TLDR: Use Resend's React Email, hack it to support MSO conditional HTML comments (see below), and port the necessary components from Cerberus or mjml.

Intro

Sending emails is a big part of how Prezly helps PR professionals to be more efficient.

Small screen responsiveness was one area where our in-house email layouts were falling short. And unfortunately there was no a quick fix for it. We had to rework the templates from the ground up.

And that's one of the big projects I've been working on in 2024.

The State of Email Development

In the beginning I was sure that the industry must have move forward significantly, developing email templates must be a breeze now.

I've been expecting to see a Next.js of emails — all necessary components already built, tested. Available right at your fingertips to use in a well-designed sexy package with amazing developer experience. Definitely in React.

To my surprise, the problem is not solved yet. The industry haven't moved far from where it was 8–10 years ago. People still have to deal with insane limitations of HTML and CSS even in relatively modern email clients. People still work around crazy issues of Microsoft Outlook 2007, 2010, 2013, 2016, and 2019. They didn't go anywhere, and they're still terrible.

Imagine building HTML pages for a half-functioning kitchen toaster from 90s, running on a Symbian OS.

Though the usages of older Outlook clients keeps declining over time, the people who use this older software usually work in big conservative organisations, which we can't just ignore.

A few classic headaches that make people loathe email markup:

Just thinking about all of these again makes my cortisol spike. 🙈

Resources

When it comes to tools, there are a few absolute gems — and yep, they’ve earned a permanent spot in my bookmarks toolbar!

  • caniemail.com for emails is what caniuse.com is for web. It's irreplaceable for finding out which HTML and CSS features are safe to use, and which you should avoid.

  • hteumeuleu/email-bugs — a Github repository documenting known quirks and bugs for popular email clients and ESP web UIs.

  • Campaign Monitor's Ultimate Guide to CSS — an excellent cheat sheet on various HTML & CSS features support in different email clients.

  • StackOverflow's Outlook conditional CSS and Email Responsiveness cheatsheets.

  • Litmus — this is Browserstack for emails. We use it for testing email markup in all email clients on any platform without having the burden of actually having those devices. A lot of useful info in their blog on typical email markup problems and workarounds.

  • Email on Acid a competitor of Litmus, providing similar functionality. They're blog is extremely useful too.

Frameworks & Libraries

Foundation for Emails

Image showing the landing page of the Foundation for Emails project.

So there is Foundation. Looks good, but it's dead. The latest commit is from 2022 (three years ago).

The dev server is nice, though it does not provide an obvious way of building dynamic templates, which is an important requirement for us.

mjml

Image showing the landing page of the MJML project.

Mailjet's MJML is (almost) exactly what I was looking for! The components library solves known cross-compatibility issues for you, out of the box!

They even have a public API to render MJML markup, though it's free and I didn't trust it to be stable enough for a production use.

It’s pretty opinionated too — only supporting fixed-width layouts, while we needed to have a mix of full-width and fixed-width content columns.

Cerberus

Image showing the landing page of the Cerberus Email project.

A nice library of components and pre-built starter templates.

Perfect for rather simple mainstream use-cases. Didn't seem to be a solid enough foundation for our complex scenario though.

Bulletproof email buttons

Image showing the landing page of Campaign Monitor's Bulletproof Email Buttons project.

Campaign Monitor's online generator for bulletproof buttons email markup. Not on the same level as other projects in this list. Nevertheless, it's a very nice microtool that deserves a honorable mention.

What about React?

We’re already using React, the whole dev team knows it inside out, and the developer experience is just amazing — seriously, the combo of component abstraction and JSX is unbeatable!

Let's see if we can use it for the job.

mjml-react

mjml-react looked very promising in the beginning. React gave the advantage of generating emails from blocks programmatically locally.

Though it comes with the exact same limitations as mjml.

What's worse is that there was no way of working them around. React JSX is only used to generate the mjml markup structure, and then the structure is fed to the mjml rendering engine (bypassing react-dom).

For example, we couldn't define our own full width <mj-body> alternative.

Resend's React Email

React Email is an amazing project under active development. Their dev server is what a modern dev server should look like! 🤩

I've decided to build on top it. For its best-in-class developer experience.

Though their components library is a meh. They claim to support "most popular email clients", but it all falls apart once you start testing it with Litmus. And no responsiveness support. That's why I had to port mjml components to React myself.

The Fatal Flaw of React

Apparently, it's impossible to render MSO conditional comments in React.

Without it, you can't use most of the existing responsive email markup tricks, you cannot use ghost tables. Without it, you cannot recreate complex Cerberus or mjml components.

The only solution hack that worked for us was to render conditionals as non-comment elements and then post-processing the HTML before returning the result (as suggested in the Github thread). I've used pnpm patch to inject this hack into React Email's internals.

I could have avoided patching the library by planting the post-processing in the user land. For example, <Head> and <Body> could render their children to strings first and then apply post-processing for MSO conditionals.

But it looked more complicated, so I've kept the patching for now.

The Final Setup

The combo we've settled with was:

  • React Email for the top-notch dev server DX
  • patched it with pnpm patch to support MSO conditional comments
  • ported most of mjml components to React
  • along with selected Cerberus components

This setup became an internal API microservice running on Node.js, seasoned with snapshot testing and Sentry error monitoring.

And after carefully porting our content blocks rendering to this new microservice, we've started to gradually enable the new logic to our customers. A few weeks later, the old renderer was fully retired — safe and sound!


Let me know what you think!

Cheers! 🖖

End of article
Got any comments?