DEV Community

Daniel Pertu
Daniel Pertu

Posted on

Nine hex codes in our only HTML email, and two of them exist nowhere else in the product

Munchable sends one HTML email. It carries a six digit code for signing in, it is 89 lines of table layout, and it is the only surface in the whole product that cannot import the palette.

The palette is a workspace package, @munchable/design-tokens. The phone app re-exports it, the web app of the same codebase uses it, the social video compositions import it. The marketing site keeps a deliberate copy in CSS. And then there is this file, which is checked into docs/email-templates/confirm-signup.html because the place it actually runs is a textarea in the Supabase dashboard.

No build step, no import, no type error. Just hex codes typed by hand.

Counting the drift

Nine distinct colours appear in the template. Six of them are exactly the palette:

#fff8ec  bg (cream)
#ffffff  surface
#3b2314  text (cocoa)
#7f5f47  textMuted
#eadcc6  border
#e7ac5b  gold
Enter fullscreen mode Exit fullscreen mode

One is a near miss. The box around the code uses #f6ecd9. The palette's biscuit tone, used for exactly this kind of inset panel, is #F5EAD8. One digit apart, invisible side by side, and no mechanism in the world will ever tell me which one was intended.

Two do not exist anywhere else in the product:

#9a8577  the footer paragraph
#b7a390  the tagline under it
Enter fullscreen mode Exit fullscreen mode

Both are plausible members of the family. Neither is a token. They were invented in the moment because the footer wanted something quieter than textMuted, and the quieter thing was never needed anywhere else, so it never became a decision.

That is what hand-copying a palette costs in practice. Not a garish mismatch, which someone would notice and fix. Three quiet colours that are almost right.

Why it cannot just import the package

Transactional auth email in Supabase is a template stored in the project's auth settings, rendered server side with Go templating:

<div style="background:#f6ecd9; border:1.5px solid #e7ac5b; border-radius:16px;">
  <span style="font-size:38px; font-weight:800; letter-spacing:10px; color:#3b2314;">
    {{ .Token }}
  </span>
</div>
Enter fullscreen mode Exit fullscreen mode

{{ .Token }} and {{ .Email }} are filled in by the auth service, not by anything we deploy. There is no bundler in that path, so there is no way for the file to read a TypeScript constant. Keeping the canonical copy in the repo at least gives the dashboard version a source of truth, a diff and a review, and anyone who edits the live one without updating the file has made the repo wrong in a way a human can spot.

The alternative is to send the mail ourselves through our own provider, which is a real option and a much bigger change: it moves sign-in email into our own deliverability, our own retries, and our own templating. For one email with one variable in it, the dashboard template wins.

The rest of the file is 2004 and that is correct

The things that look dated are all deliberate:

  • Tables for layout, because that is still what mail clients lay out reliably.
  • Every style inline, repeated per element. The font stack is written out seven times in 89 lines.
  • A hidden preheader div, so the inbox preview reads "Your Munchable confirmation code is 123456. It expires in 60 minutes." rather than the first words of the body.
  • <meta name="color-scheme" content="light">, because Munchable is a light-only product and a client inverting the cream into charcoal is not a dark theme, it is a broken one.

The webfont links are the one piece of near-theatre. The comment above them says it plainly: Apple Mail and iOS Mail will load them, everything else falls back to the system stack. So the brand face shows up for a minority of recipients, every inline style carries the fallback chain anyway, and the links stay because the cost is one request in the clients that honour them.

The copy is the part I spent longest on

You're receiving this because name@example.com was used to create a
Munchable account. If that wasn't you, you can safely ignore this
email. The account stays unconfirmed and nothing is set up.
Enter fullscreen mode Exit fullscreen mode

Someone typing your address into a sign-up form is a thing that happens, and the usual version of that sentence tells you to ignore the mail without telling you what happens next. "The account stays unconfirmed and nothing is set up" is the sentence that means you can actually stop thinking about it.

The code paragraph does the same job for the other direction: it says the same code works on the web app and the phone app, because the one thing a person holding a six digit code wants to know is whether they are in the right place to type it.

Where the palette is supposed to live

If you want to see the colours as they are meant to be, the site is the reference. munchable.app is the cream, the cocoa ink and the gold outline in their native habitat, munchable.app/recipes is a wall of the inset panels the code box is imitating, and munchable.app/conditions shows the same type scale at full length.

One email, nine colours, six of them true. The useful lesson is not "centralise your tokens", which everybody already agrees with. It is that the surfaces which cannot import them are exactly the surfaces nobody looks at twice.

Top comments (0)