Sustainable Code Through Collaboration: React Email Bug Fixing

Sustainable Code Through Collaboration: React Email Bug Fixing

Introduction

Over the past few months, I had the opportunity to work closely with my team (Array of Sunshine) and mentor Piranavan Selvanandan to resolve a persistent bug within React Email. This experience taught me about package managers such as PNPM, symbolic linking of local files, careful testing, and applying effective problem-solving skills in a real-world context. In this post, I’ll share insights into the code we worked with, the challenges we faced when replicating the bug, and the final solution our team was able to produce.

What is React Email?

React Email is an email formatting and styling tool created by Resend. The tool uses React components and Typescript to beautify emails and fix formatting issues that plague the current email market. React Email is important because it addresses long-standing issues and outdated tools that email clients have failed to fix since 2010.

For example, if we take a small business that sells clothing online to customers around the globe, and that business wishes to send out emails to their customers promoting a brand-new item in stock, they may struggle to make sure their emails are formatted correctly. This is important not only for maintaining brand status but also for ensuring that the user is able to easily access and read the email. However, considering there are so many email platforms on the market currently (Outlook, Google, Yahoo, etc.), making sure that every email client formats the message correctly can be a major time waster and very irritating.

This is where React Email comes in and eases the issues of cross-platform integration by converting React components into exported HTML that can be read by all email platforms. This not only lessens the time the business must spend reformatting emails but also helps maintain consistent business identity. However, this is only one example of how React Email can improve the email-sending experience. This tool has become globally accessible to many businesses, both large and small, as well as to individuals who use it for everyday email sending and the numbers reflect its growing importance. According to npmcharts, React Email is currently sitting at over 1,600,000 npm downloads, with users leveraging this tool to enhance their email-sending experience.

HTML Formatting Issue

Our team was assigned to tackle GitHub issue #1767, titled “Incorrect display of quotes in styles and string links when exporting in React Email.” The poster of the issue mentioned that the bug stemmed from exporting HTML within the <style> tag, which resulted in an escape character (&quot;) being used when placing font family names in the style sheet.

For example, if the user wanted to specify a style for the <body> tag in React the user typically would write it as:

Article content

The correct formatting that suppose to have been produced within the code should have been:

Article content

Instead the program would reproduce escape characters around the quotes within the HTML Export:


Article content

Within the comments of this issue, our team noticed that the problem wasn’t limited to the style attribute. It was also affecting href links, specifically those containing the ampersand symbol (&). We also discovered that this style attribute issue didn’t only affect the <body> tag, it was impacting all other tags within the scope of our issue as well.

Article content
Image showcasing the replicated Issue within React-Email. This was created within our testing environment, details about this environment can be found within the "Challenges" section.

When tackling this problem head-on, our team decided to take the first steps in identifying the source of the bug. Our initial hypothesis was that the issue might stem from how the React component was being parsed into an HTML string. This led us to investigate the packages folder within React Email. Inside the code-base, we found several components and functions that support the program.

Article content
Internal Structure of React-Email's package folder. Note how all HTML Component folders represent HTML element tags.

When we took a closer look at the packages, we discovered that the components served as templates for HTML tags, allowing React components to maintain their formatting and styling. However, they didn’t lead us to the point where the parsing was executed. Instead, we found that the HTML export functions were primarily contained within the React Email Render package, specifically in two render.tsx files.

Article content
Screenshot of the Render package along with a highlight showing where our solution code would be placed.

These render.tsx files contained the code responsible for parsing the React components into HTML strings. The files also included React Email’s external package extensions: plain-to-text, which converts the HTML string into plain text by removing all HTML tags and focusing primarily on the content within the tags, and Prettier, a formatting tool that takes HTML strings and converts them into a more readable format. If neither extension is called, the program simply returns the HTML string as is.

Inside React-Email: Code Base Overview

Tech Stack

Article content

Flow of Control:

The course of action a user must take to export a React-Email template into an HTML string works as:

  1. User Action: The user adds React Email to their React project using a package manager (npm,pnpm, or yarn)
  2. React-Email Imports: The user creates a new component (e.g., MyEmailTemplate.tsx) and imports necessary React Email components such as <Body>, <Text>, <Img>, etc.
  3. User Action: The user writes the content and styling of the email using the imported components and applies inline or utility-based styles (e.g., Tailwind CSS). This template can now be connected to an email client or automation service for sending.
  4. React-Email Render: To ensure cross-platform compatibility, the user implements a render function using React Email’s render() utility to convert the React component into an HTML string.
  5. Implementing Prettier (Optional): The user can optionally improve the readability of the exported HTML by enabling Prettier formatting within the render() function by setting pretty: true.

Challenge: Setting up a Testing Environment

We faced several challenges in determining how to start the process of recreating the bug and identifying where to focus within React Email. The first major hurdle was recreating the bug itself and understanding how React-Email works. To tackle this, our team divided the work, with each member investigating different approaches to recreate the bug and set up an environment where we could modify the code within React Email.

When trying to figure out how to recreate the bug and understand where to begin the debugging process, I broke the problem down into steps. My first step in problem-solving was to review React-Email’s documentation to learn how users implement the formatting package in their projects and how it’s used. I discovered that, in order to test the features within React-Email, I would first need to create a new project, download React-Email via NPM, import its components, and export the results to the browser console. With this in mind, I created our own testing environment, which can be found here.

Article content
Image of our testing environment reproducing the bug within our browser and console.
Article content
Image of our component that we used to test React-Email components and how we exported the HTML string to the console.

While this solution helped us replicate the bug and find a way to test React-Email’s components, there was one issue: our current import of React-Email wouldn't reflect any changes made in our local forked repository. The only way we would have been able to see our changes was by making a pull request to React-Email, which obviously wouldn't work for our purposes. This led to our second challenge: how could we implement the changes we were working on and export them to our testing environment? 

Connecting repositories was something I had never personally worked with before. However, after some research, I discovered that the solution to the problem was to use symbolic linking by connecting my local files with each other using npm link. In my terminal, I navigated to each of my files and created a global link between the two, hoping this would apply the changes from one file to our testing environment. Unfortunately, this approach led me to a roadblock. Despite successfully creating a global link, the changes I was making to React-Email weren't automatically reflected in the testing environment as I had hoped.

Due to my inexperience with symbolic linking, I found myself at a roadblock, having exhausted all my options, and ultimately had to ask for help. Our mentor, Piranavan, made himself available for one-on-one sessions to assist us when we got stuck. He helped me understand why the issue was happening and guided me through the proper way to link the repositories. We worked together, testing and troubleshooting the linking problem. Eventually, Piranavan found a solution that fixed the connection issue. However, the process was slow, and he recommended that our team create a testing environment within our forked repository to streamline future testing.


Article content
Diagram showcasing how our forked React-Email repo symbolically links to our testing environment.

Sadly, due to time constraints, we decided to continue with the current state of the testing environment. However, for future bug fixes and iterations, I believe it would be best to create a new testing environment within React-Email. As a result, I plan to implement these changes for the next bug fix.

Our Solution

After our initial struggle with fixing the testing environment, our team quickly shifted focus to finding a possible solution to the problem. We found one potential fix using an encoding package known as HE. While HE successfully resolved our original escape character issue, it introduced a few complications. These complications entailed:

  1. Though the escape character problem was fixed, it seemed to have caused an over correction, removing escape characters outside of the HTML tags as well. While this might appear to be a good solution, it could cause issues if the developer intends to include escape characters in the email content.This fix inadvertently alters something the user may not have wanted to change.
  2. Additionally, there was now an issue with HTML formatting showing static errors when printing the exported HTML (described below)

We decided to take a step back and think about why this fix wasn’t working as intended. After reviewing the code in our testing environment, we noticed that while escape characters like &quot; were being decoded into their corresponding characters, the resulting HTML still had formatting errors. For example, the correct formatting for this code should be:

<body style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif"></body>        

However our code (implemented with HE) was producing:

<body style="font-family: "Helvetica Neue", Helvetica, Arial, sans-serif"></body>        

This incorrect HTML formatting prevented the font from being implemented as intended. Based on this finding, we explored different approaches to ensure the exported HTML followed the correct formatting for the style tag. During my research to find an algorithm or function to replace these character quotes, I discovered a way to implement a check within the style and href tags using regex.

In my research, I learned that regex is a tool used to search, match, and manipulate text based on specific patterns. It consists of a sequence of characters that define a search pattern. These patterns can be used to find text, validate input, or replace text in strings. Given that our bug was caused by incorrect formatting from characters, I considered adding a check within the Render package—specifically in the render.tsx component, located in both the Node and Browser folders. If this check can detect escape characters, it can prevent these unwanted escape sequences or incorrect characters from passing through into the final HTML export.

Our solution can be seen here:

Article content
Screenshot showcasing our regex solution.

You can see how the regex function was integrated into our project. In lines 1-3, we've added an html.search() statement to check for each escape character symbol that appears within the attributes. If an escape character is found in the style or href attributes, it is assigned a true value (1) or if no escape characters are found then it is given a false value (0). When double or single quote escape characters are detected, they are replaced with single quotes (‘). If an ampersand escape is found in the href attribute, the escape characters are replaced with the ampersand symbol (&). If none of these characters are found, the regex functions are ignored, and the HTML is exported as-is. After we implemented our solution we created a pull request to be reviewed by Resend. The pull request included in this document can be found here.

To ensure our solution was correct, our team used the testing environment we created earlier to examine the exported HTML produced in the console. To visualize all the possible tags that could be used by a user, we updated our testing component to include every potential React-Component tag. Using this component, we were able to compare the outputs of the style and href attributes. We also inserted temporary console.log() statements throughout our code in React-Email to check if our solution successfully detects any escape characters within the tags.

Additionally, we created a testing table and recorded our results whether the program passed or failed the tests. This tests that we preformed checked our results before implementing our regex code with and without prettier enabled and after our solution was implemented. The reason our team tested our solution with Prettier is because we wanted to ensure that our solution did not cause any issues with the formatting extension enabled.

Article content
Image of our updated testing component that implements all possible React-Email components to test our methods.
Article content
Image of the results from our updated code implementing Regex. Note how all style attributes within the HTML tags are now replaced with single quotes and console logs that mark if our tag contains escape characters.


Article content
Article content
Table Diagrams that display the tests we preformed to ensure our solution worked as intended. We completed four different tests. Before implementation with/without prettier enabled and after implementation with/without prettier enabled.

As shown in the screenshot above, with our solution implemented, we successfully replaced the escape characters with single quotes. Our solution also resolves the initial HTML tag formatting issue by replacing the incorrect quotation marks with the correct symbols. Therefore showing us that our regex solution seems to have fixed our bug and with our testing the check is passing throughout all components.



To view or add a comment, sign in

More articles by Tamara Slone

Others also viewed

Explore content categories