mobslgcy
← All work

Tooling · 2026

Heddlemail

A WYSIWYG email builder that refuses to send anything its preview did not show.

Role
Design and build
Timeline
2026
Stack
TypeScript, React, Zod, Vitest
Links
Live site ↗ · 2 min read
The Heddlemail landing page: the headline “Lay out email like a design file”, a list of export targets, and the editor below with Insert, canvas and Button properties panels.

The problem

The previous email builder had the worst kind of bug: the preview looked perfect, the email went out, and part of it was missing. Nested content simply vanished from what was sent. No error, no warning — just quietly wrong emails reaching real inboxes.

A builder whose preview cannot be trusted is worse than no builder. So this was a rebuild around one guarantee: what renders on screen is what ships.

Finding the cause

I traced the vanishing content to the exporter. When it met a structure it did not handle, it did not fail — it returned empty output and carried on. Every unhandled case became silent data loss.

What I built

A compiler that refuses rather than guesses

The export step is now a compiler with a strict contract: if it cannot faithfully produce a piece of the template, it refuses to emit and says why. A loud failure in the editor is cheap. A silent one in a customer's inbox is not.

Inputs are validated with Zod at the boundary, so malformed templates are caught before they reach the compiler at all.

One code path for preview and export

The root cause of the drift was that preview and export were two different pieces of code doing "the same thing". Now they are the same code path. The preview is the compiled output, so the two cannot disagree.

Every template is a test

Every template is wired into the Vitest suite. If the compiled output of any template changes unexpectedly, the build fails, and nothing ships until someone looks at the difference and accepts it.

Something here caught your eye?

Tell me about the product you’re building, the role you’re hiring for, or the problem you’re stuck on. Pick a coffee chat, a consultation or a hiring conversation.