LinkSquares · Design Systems

Removing the design bottleneck from transactional email

Every transactional email at LinkSquares was a one-off designer ask. I built a code-first system, plus a plain-language generator, that put engineers and PMs in control of shipping email on-brand, and won the architecture decision that made it possible.

View the live system
Role
Senior Product Designer · End-to-end
Scope
Design system · Internal tooling
Layers
Foundations, components, templates, generator
Adoption
Engineering, PM, design lead, all teams
Outcome
Took designers out of the critical path for transactional email, without trading off the brand.

01 · Problem

Every transactional email was a one-off

The business need was simple: ship transactional email faster, on-brand, without designers as the bottleneck. The system was the only way there.

At LinkSquares, every transactional email was a one-off designer ask. Password resets, invitations, receipts, status updates. Each one pulled a designer in, and each designer interpreted the brand a little differently. The result wasn't bad design. It was inconsistent design, which is its own kind of brand damage.

And it scaled badly. Every new transactional surface meant another designer ticket. Engineering couldn't ship an email on their own without breaking the brand, and they didn't want to. Designers were the gating function for a class of work that should never have needed design review in the first place.

Root cause
The brand and the components only lived in Figma. Designers gatekept. Engineers couldn't access the source of truth. Brand drifted at every handoff.

02 · Decision

A code-first system, plus a generator

Most design systems live in Figma. But every transactional email at LinkSquares already passed through engineering, so a Figma source of truth would mean someone (usually a designer) translating into code every time. That recreates the bottleneck I was trying to remove.

Code-first flipped the model. If components lived where engineering already shipped, designers came out of the critical path by default. The system was built in three layers: foundations, components, templates. On top of that, a plain-language generator. A PM or engineer could write "send an invitation to a new admin, urgent tone, with a CTA button" and the system composed it on-brand.

Layer 01
Foundations
Color, type, spacing tokens. Pre-set to LinkSquares purple, orange, and the email-safe type stack. Anything built with the system inherits the brand automatically.
Layer 02
Components
Header, headline, body, button, badges, lists, status box, card, footer. The building blocks of any transactional email.
Layer 03
Templates
Canonical compositions for password resets, invitations, receipts, notifications. The same components arranged into known transactional patterns.
On top
Plain-language generator
Describe the email you need. The generator returns a structured email composed from the system, on-brand by default. No designer required for new transactional surfaces.

Designers extend the system when something new is needed. Everyone else composes from it.

03 · Argument

The architecture call I had to defend

My manager pushed back on the architecture. He wanted the system to live in Figma, because he worried that if it lived in code, no one outside engineering would be able to edit it.

I argued the opposite. The problem we were solving was precisely because the brand and the components only lived in Figma. Designers gatekept. Engineers couldn't access the source of truth. The brand drifted at every handoff. Putting the system in Figma would solve nothing.

Rejected
System lives in Figma
Familiar to designers. Familiar to my manager. Recreates exactly the gatekeeping that caused the problem.
Shipped
System lives in code
One source of truth that engineering, PM, and design can all touch. Composes real emails, not previews of them.

The second piece of the argument was timing. AI coding assistants like Cursor had just made code accessible to anyone who could write a prompt. The "only engineers can edit code" objection had stopped being real. I made the case that the architecture should be built for where teams were heading, not where they had been.

The system shipped in code. About a year later, the company rolled out Cursor accounts to every designer at LinkSquares. The architecture had been waiting for them.

04 · Adoption

Picked up across the company

The system became the source of truth for every transactional email at the company. The handoff that used to require a designer no longer required one.

Roughly 8 to 12 transactional email categories run through the system. Engineering reaches for it whenever a feature ships with a new notification, typically once every three or four sprints. What used to be a two-day designer ask now takes about thirty seconds: an engineer or PM types a prompt, the generator composes an email from the system, the brand holds.

The system also stays alive without me at the center of it. When something doesn't quite fit the existing patterns, a designer makes a quick adjustment (my manager added a table component when an analytics email needed one) and that pattern becomes available to everyone else next time. The generator handles the long tail. Designers extend the foundations only when net-new patterns are needed.

Impact

What this delivered

05 · Reflection

What this is, in the end

By the time the system was running, my involvement in any given email had dropped to nothing. Engineering wrote the prompt. The generator composed the result. The brand held. That was the design.

The work doesn't show up as a beautiful single artifact. It shows up as the absence of friction across every team that ships email at the company.

What I'd push further

The system isn't finished. Engineering can still write off-system emails if they want to, and a few did. I'd occasionally find a one-off wonky subject line and have to point the engineer back to the styleguide. The pattern I built scales well within the existing 8 to 12 categories, but it's not yet a multiplier for net-new ones.

With another quarter, I'd add guardrails inside the generator: a check that flags when a requested email is too far off the existing patterns and routes it to a designer, plus a way for non-designers to add new templates through the generator itself. The system is currently a multiplier for existing patterns. The next horizon is making it a multiplier for new ones.

View the live system
Foundations, components, templates, and the working generator