Making your retail email template library work smarter, not harder

The curse of the retail email template! Should you display 10 products using 5 rows of 2? Or 9 products using 3 rows of 3? Perhaps 10 rows with each product on it’s own? For most companies, testing which email structure works best is a royal pain. Well, I’m here to explain how one SparkPost template can support any combination of rows and columns for any retail email template and beyond.

retail email template rows and columns

The ability to apply any row/column combination using one template is achieved by the combination of a flexible data-driven template with the structure of the data being sent to the template. When using SparkPost’s Transmission RESTful API, your application will determine the look of the email by changing how it organizes the product information it sends to the template. To consume the data properly, SparkPost’s conditional loop statement, each, is used within the template. In this example, the each statement is needed twice; one nested in the loop of the other. The outer each represents rows while the inner use of the each loop will drive the number of columns, using products from our JSON, for each individual row.

Before reviewing the template code/HTML, let’s look at some sample input data. Shown below is a JSON structure that holds the product data for 4 rows with each row having product data for any number of products. This product data would be placed in each substitution_data stanza for each user.

The data above represents 4 rows of products with rows 1, 2 and 4 having two products and row 3 having one product.

In JSON speak, we have two arrays of data, rows and products. The template will loop through each array depth-first until it has processed all of the rows of data. To change what the email output looks like, simply change the structure of your data – how many rows there are total and how many products there are for each row. This means you theoretically have an unlimited number of ways to represent your data, all using one template.

The above sample is actually a fairly simple example where we are only sending the image URL, the price and a (sub)title for the picture. What if each product had a set of features to display, or maybe product categories as well. In the real world there may be a landing page URL, title and subtitles, discount prices and a host of other bits of information. I only bring this up in order to demonstrate that SparkPost’s templates can handle any depth of JSON arrays. Here is a sample of what one of the product structures might look like if it had a set of features:

Now let’s examine the template code that will loop through the above data producing 4 rows showing 7 products.

[Note: In this example, I’m creating a new table for each row. This isn’t mandatory, it’s just the approach that I’ve taken for this example.]

Here is the output:

retail email template output images

The magic starts on row 8 with the first each statement which represent each row of products. Then, on row 14 we have the second each statement that will loop through all of the products for a row. The rest of the code is just table, row and column tags along with a few lines to actually display the images, titles and price.

A more advanced example

Now let’s take this to another level – hey this is an advanced topic after all! I am going to demonstrate how to minimize the size of the JSON structure and the data sent from your application to SparkPost. For a simple use case, what if we want to offer the exact same products to a second user but without row 3? That means we have to send all of that data again minus the data that represents row 3. When you are sending hundreds or thousands of emails, the amount of data may not seem like much. However, when you’re sending millions or billions of emails, the savings in time and bandwidth can be significant.

We can minimize the amount of data to be transferred by moving the product details out of the individual user’s substitution_data and placing it into a global array that is available to each user within a Transmission API call. In order to get the best throughput out of SparkPost and be most efficient with data transfer, SparkPost suggests that large bulk mailings be grouped into multiple Transmissions calls, each containing anywhere between 5,000 – 10,000 users. That not only increases throughput due to reduced connection setup overhead, but it also lowers the risk of connection issues since you will cut down the number of connections by 4 orders of magnitude. SparkPost can handle individual calls at that scale with high throughput, but consolidation of transmission calls does bump up the overall speed of message generation and delivery.

In order to use this approach, minor changes are necessary to both the JSON structure within the Transmission API call, and the HTML template.

Let’s look at the JSON data first. This example is going to be a little more detailed in order to show two unique emails being sent from the same Transmission API with the same product information.

The first step is to move the JSON data for each product to be displayed up into the global substitution_data section. The orange highlighted products key is the start of the product array. Unlike the product data that was placed in the recipient substitution_data from the first example, each set of product information now needs a unique key which is indicated by the green highlighted fields. The products array is different from a typical JSON array. Notice that there is NOT a set of square brackets, [], surrounding the products. Taking this approach allows us to go directly to each product data set without knowing where they are in the products array. If you look at the substitution_data  at the individual recipient level, which are denoted by the aqua highlights, you will see a familiar row/product structure from the last example. The difference this time is that instead of the product details, the recipient substitution_data fields only have an id field. That is our link back to the detailed product information within the global substitution_data  set and drives which products will be shown for each user. If you look at both recipient users, they both have different sets of products to display and each has a different format. The first recipient is using the same 4-row format of the first example, while the second recipient will get two rows of products, 1 in the first row, and 3 in the second row.

The only changes that we need to make in the template is how we reference the field(s) we want to display.  The first part of our reference is to the products array.  Next we index to the id that we are interested in, then the field name itself.  So to use the product_url, we have:


(Note: Please refer to the SparkPost documentation to further understand how to use arrays and the loop_var keyword)

Here is the full html template code:

So that’s it. By creating a two level array of rows and columns, along with some of the other topics discussed in previous blog posts, any company can dramatically consolidate their retail email template library while simultaneously increasing flexibility and customization.

Happy Sending,

Jeff Goldstein

Questions around these retail email template examples? Or email templates in general? Drop us a line below, on our community slack or Twitter.