Home Blog Contact
Home/Blog/Rebuilding Abandoned Cart Emails for Each Sho…
ArticleRevOpsHubSpotWooCommerceAutomation

Rebuilding Abandoned Cart Emails for Each Shopper

5 min readBy Miloš Mitrović

A luxury ecommerce store was sending one generic abandoned cart email to every shopper. I rebuilt it so each email shows the shopper their own items and routes different product collections to different designs, from a single template with no per send manual work. Here is how the engagement went, from the problem to the build and the parts that were tricky.

At a glance

  • Client: A luxury ecommerce store running WooCommerce for the storefront and HubSpot for lifecycle email.
  • Challenge: One generic abandoned cart email went to every shopper, ignoring the specific items they had added.
  • Approach: A single HubSpot template that renders each shopper's own cart from synced contact properties, plus a workflow that routes product collections to different designs.
  • Result: Every shopper now sees their exact items and the right collection design, from one template that needs no per send manual work.

The context

The client is a luxury ecommerce store. The storefront runs on WooCommerce and lifecycle email runs in HubSpot. I was brought in to fix the abandoned cart recovery email, which at that point was a single design sent to everyone. My role was to design and build the system end to end, from the data sync to the email and the routing logic.

The problem and its constraints

The abandoned cart email was one generic reminder. It told a shopper that a cart existed but never showed what was in it. For a store whose appeal is the specific product, that is a weak recovery tool, and around 70 percent of ecommerce carts are abandoned, according to the Baymard Institute, so the email was leaving a great deal unrecovered.

Three constraints shaped the build. Each email had to show a shopper their real items with no one hand building an email per customer. Different product collections had to be able to receive different designs. And it all had to render correctly across email clients, including Outlook, which is where email builds usually break.

What was in place before, and why it fell short

The store relied on a single static email. A designer could restyle it, but the content was fixed: the same copy and the same generic prompt for everyone. Nothing connected what a shopper had actually added to what the email showed. The only way to make the message relevant was to build a separate email by hand for each case, which does not scale.

What I built

I connected WooCommerce to HubSpot with a connector that syncs abandoned cart activity onto the HubSpot contact record as custom properties. The one that matters for email is a prebuilt HTML table of the cart contents, with image, name, quantity, and price. The product names, SKUs, and categories sync alongside it and drive the routing.

Rendering each shopper's own cart

A single template pulls each contact's own cart at send time. The mechanism is a personalization token with the safe filter inside an HTML module:

{% if contact.abandoned_cart_products_html %}
  {{ contact.abandoned_cart_products_html | safe }}
{% else %}
  <p>Your saved items are waiting for you.</p>
{% endif %}

HubSpot escapes HTML stored in a property by default, so a plain token printed raw code on screen. The safe filter was what turned the stored table into a rendered cart, and the conditional kept the section clean for contacts with no cart. One template then produced a different, correct cart in every inbox.

Routing collections

Because the product, SKU, and category values sat on the contact, I built a HubSpot workflow that branched on them. It enrolled a contact when cart products were known, tested each branch for a collection keyword, sent the matching design, and fell back to a generic email when nothing matched.

What was tricky, and the calls I made

  • The HubSpot editor never resolves personalization tokens; the canvas only shows the token name. I could verify rendering only with a real send or a preview as a specific contact, so testing moved off the canvas entirely.
  • Branch order mattered. HubSpot follows the first branch a contact matches, so for carts holding more than one collection I ordered branches by priority and left the generic email last.
  • Exact match conditions rarely fired, because the products property is one delimited string. I switched to the contains operator and confirmed the keyword actually existed by reading real contact values before relying on it.
  • Outlook was the hard part. It renders with Word's engine and ignores most CSS, and the injected cart HTML could not be styled from inside HubSpot. To get Outlook right I edited the cart template at the WordPress source, building inline styles and VML into the markup so the design held there too.

The outcome

The store went from one generic reminder to an email that shows every shopper the exact items they left, with collection specific designs handled by the workflow, all from a single template that needs no per send work. Each email reflects the live cart at the moment of abandonment, so it matches what the shopper actually had. I did not run a formal before and after study on this engagement, so I will not put a recovery figure on it. The change is structural: the email became relevant to each shopper instead of generic to all of them.

Sources

M
Miloš Mitrović
Email Marketing for Ecommerce

Have a question or a project?

Whether it is about this post or a system you want built, I'm happy to talk.

Get in touch

404

Post not found. It may have been moved or the link is incorrect.

← Back to the blog
Summarize with AI
ChatGPT, Perplexity, and Grok open with the prompt ready to run. Claude, Gemini, and Copilot open a chat with the prompt copied; press Ctrl+V (Cmd+V on Mac) to paste. The full text is included, so it works even without web access.