Skip to content
Ship every weekUI and contentemail

Product emails

Welcome notes, receipts, and alerts, ready to send from day one.

Your app needs to send email: welcomes, receipts, export links. Here they are typed React Email and MJML templates in your codebase, with a shared responsive theme and local previews. Both formats and plain HTML work through the same server-side helper.

  • 1 path every email goes through
  • 5 ready-made email templates
  • 0 email secrets in browser code

How it works

The mechanism end to end, as implemented in the repository.

  1. 1

    Choose or write a template

    Use a typed React Email or MJML template with props for names, amounts, and links. Five templates share one responsive layout, and the local studio previews desktop, mobile, text, and source.

  2. 2

    Send from the server

    Your server code or a background job calls one send helper with the component, a to-address, and a subject. The helper reads server-only config, so it can never end up in browser code.

  3. 3

    It renders and delivers

    The helper turns the component into HTML and hands it to the email provider. If the provider fails, the error is thrown so background jobs retry instead of losing the email.

  4. 4

    No keys, no crash

    If the email keys aren't set, the helper logs a warning and returns. Local dev and CI run fine without provider credentials.

Interactive example

See it working

This walkthrough demonstrates the implemented backend contract without using an account, credentials, or provider calls.

Interactive example

Explore the implemented decisions

Choose a sample state
Welcome component

Deterministic sample data only. No account, provider, or network connection is used by the interaction.

The problem this solves

Without a shared foundation, every team rebuilds these edge cases — differently.

The template that broke without telling you

Your emails live in a vendor dashboard. Someone renames a variable in the app. Weeks later a customer sends a screenshot of a receipt that says {firstName}. Here, templates are typed code: that rename fails the build instead.

Five features, five ways to send email

Each feature spun up its own email client. Now from-addresses don't match, errors get swallowed differently, and switching providers means hunting through the whole codebase. Here there's one send path to change.

New teammate, day one, blocked

The app crashes on boot because they don't have an email API key. So they either beg for production credentials or wrap every send in if-statements. Here, missing keys just turn sends into logged skips.

Highlights

Why it matters

Emails are code, not dashboard blobs

Five ready templates live in your repo as typed React Email functions with matching MJML variants. Change them like any other code, with review and version history.

One door for every send

Every feature and background job sends through the same helper, so the from-address, styling, and error handling live in one place.

Works without keys in dev

No email API key set? Sends log a warning and skip. Nothing crashes, and nobody needs production secrets to run the app locally.

Engineering guarantees

What this does and does not promise

Safety boundary

The feature page previews what templates look like; it never sends real mail. Getting email into inboxes (domain setup, deliverability, provider uptime) is still between you and your provider.

Implementation evidence

The boundary above is code, not a claim. These files carry the contract:

  • src/lib/email.ts
  • src/lib/email/templates
  • src/features/privacy/jobs.ts
Questions

Frequently asked questions

Build on the product emails foundation

The docs describe the same contracts this page demonstrates.