Rendering Emails with Isomorphic Relay

My name’s Aaron Horton, I’m a front-end engineer at 1stdibs and I’m really excited about emails!

If this sounds like a contradiction to you, you’re not wrong; developing email templates is, generally, not the most thrilling task for a front-end engineer. Email clients aren’t up-to-date with the newest rendering engines so CSS support is relegated to inline styles and layouts are required to be table-based. However, we’ve been working on a new email-authoring framework that is exciting, and I wanted share it.

The problem with emails

Our emails are triggered from our back-end when an email-worthy thing happens (new message, new order, etc.). Prior to our new framework, a dedicated email service would find the correct template, pass variables to that template, compile it to HTML, and fire it off from our server or ESP. In order to update a template in any meaningful way, a front-end engineer had to work with back-end to figure out what data is required from the service (essentially forming a unique contract for every email), then roll up their sleeves and start updating the raw template.

As you might imagine, we front-end engineers weren’t clamoring to update email templates. We don’t have access to any of the shared resources and tooling that we’ve developed for our Node/React/Relay/Graphql stack. Instead, we have shared snippets of HTML, variable naming conventions, and… not much else. It was difficult to develop new templates, and as our stack evolved, email templates fell further and further behind. We decided that a fundamental rework was required.

Incorporating server-side Relay

The idea was to write server-side Relay using Isomorphic Relay, render it to a string of HTML, and then send it as part of a response to the aforementioned email service. This greatly simplifies the contract between front-end and back-end. We can simply grab, for example, a transaction ID and use Graphql to satisfy the data requirements, adjusting them on the fly without the need to renegotiate every field with the back-end whenever a change was required. It also allows us to use the handy Graphql computed fields that we’ve been developing for use in our web apps. On the HTML level, we gain access to React’s more legible component-based structuring, easy testing with Jest, and, perhaps most importantly, we make the React developers that we have at 1stdibs feel more at home working on email templates.

We decided to tackle the initial use-case of transaction-related emails. We’re an ecommerce site and ensuring that buyers and dealers have clear and timely updates on their orders is a high priority. We started by building a simple Express app that takes a template name and a transaction ID as parameters and responds with JSON that includes both a subject line and HTML content. For example, a request such as GET emails/TestTemplate?transactionId=123456 returns JSON that looks like this:

The HTML that’s returned is output from React’s render-to-string functionality. We construct our query config in our Express route, and each template is itself a Relay container that stipulates its own data requirements.

One feature that I like is the ability to easily return either HTML embedded in JSON or raw HTML. This makes testing during development much simpler. With our prior setup, it was nontrivial to test your emails, but with our new framework, seeing your changes is as easy as yarn install && yarn start and hitting localhost in your browser. Moving to React also gives us access to snapshot testing with Jest.

Conclusion

Emails are essential to how 1stdibs operates, but have always been a little painful to deveop. Rethinking the way that we handle email allows us to be more flexible and efficient in our development and makes it easier for both product and engineering to iterate. As excited as I’ve been to work on this framework, I’m just as excited to see what it will help us to do next.