VibeWeek
Home/Grow/Email Template Implementation: React Email, MJML, Plain HTML, and the Patterns That Don't Embarrass You in Outlook

Email Template Implementation: React Email, MJML, Plain HTML, and the Patterns That Don't Embarrass You in Outlook

⬅️ Day 6: Grow Overview

If you're running a SaaS in 2026, you send a lot of email — welcome emails, password resets, receipts, notifications, digests, lifecycle drips. Most founders default to a string-template ("Hi ${name}, your...") with inline HTML, then six months in have 47 templates scattered across the codebase, each rendering subtly differently in Outlook 2016, with the brand colors slightly off in three of them. Email rendering is one of the most-frustrating frontends — it's like building UIs for a browser frozen in 2008.

A working email-template system answers: how do we author templates (React Email / MJML / plain HTML?), how do we maintain consistency, how do we handle dynamic data, how do we test rendering across clients, and how do we send through providers (per VibeReference: Email Providers). Done well, emails feel native to your brand and render reliably; done badly, every email is a one-off design + engineering project that breaks for 30% of recipients.

This guide is the implementation playbook for email templates in 2026 — picking the authoring approach, the design discipline, dynamic-data patterns, multi-client testing, and shipping templates without the Outlook nightmares.

Pick the Authoring Approach

The biggest decision is HOW you author email templates. Get this right.

Help me pick an email-template authoring tool.

The five options:

**Option A: React Email (recommended for most teams in 2026)**

```tsx
import { Html, Body, Container, Text, Button } from '@react-email/components';

export function WelcomeEmail({ name }: { name: string }) {
  return (
    <Html>
      <Body>
        <Container>
          <Text>Welcome, {name}!</Text>
          <Button href="https://app.example.com">Get started</Button>
        </Container>
      </Body>
    </Html>
  );
}

Pros:

  • React component model
  • Type-safe props
  • Live preview during development (react-email dev)
  • Compiles to clean HTML
  • Tailwind support
  • Reuse components across templates
  • Same code = render to HTML or PDF (per pdf-document-generation-tools)

Cons:

  • React-specific (Next.js / Node mostly)
  • Compiled HTML still has email-specific quirks

Option B: MJML (markup-driven)

<mjml>
  <mj-body>
    <mj-section>
      <mj-column>
        <mj-text>Welcome, {{name}}!</mj-text>
        <mj-button href="https://app.example.com">Get started</mj-button>
      </mj-column>
    </mj-section>
  </mj-body>
</mjml>

Pros:

  • Industry-standard markup for emails
  • Compiles to bulletproof email HTML (table-based)
  • Strong Outlook compatibility
  • Language-agnostic (Node, Ruby, Python, Go)
  • Good for designers / non-engineers

Cons:

  • XML-y; verbose
  • Less component reuse than React Email
  • Templating engine separate (Handlebars + MJML, etc.)

Option C: Plain HTML email (the legacy way)

<table role="presentation" cellpadding="0" cellspacing="0" border="0">
  <tr>
    <td>Welcome, ${name}!</td>
  </tr>
</table>

Pros:

  • No build step
  • Direct control
  • Works anywhere

Cons:

  • Tables and inline styles everywhere
  • Hard to maintain
  • Bug-prone

Option D: SaaS template builders (Postmark / Mailmodo / Stripo)

GUI-based template editors hosted by your email provider.

Pros:

  • Non-engineer can edit
  • WYSIWYG preview
  • Provider-tested rendering

Cons:

  • Vendor lock-in
  • Limited dynamic logic
  • Templates not in your code repo

Option E: Marketing-tool-specific (Customer.io / Klaviyo / Iterable templates)

If using a marketing automation platform (per VibeReference: Email Marketing Providers), use their template editors.

Pros:

  • Tightly integrated with audience / triggers
  • Marketing team can edit

Cons:

  • Marketing emails only (not transactional)
  • Vendor lock-in
  • Two template systems (transactional + marketing)

The 90% answer for indie SaaS in 2026:

  • Transactional + lifecycle: React Email (or MJML if not React-shop)
  • Marketing broadcasts: marketing tool''s editor (Customer.io / Loops / Resend Broadcasts)

Don''t mix authoring approaches within a category.

For my system:

  • Stack (React / Vue / Go / Python?)
  • Sender mix (transactional / marketing / both)
  • Team (engineers / designers / marketers)

Output:

  1. The authoring choice
  2. The setup plan
  3. The migration plan if changing

The biggest unforced error: **plain HTML email-templating with string interpolation.** Six months in, every template has bespoke code; nothing reuses; testing each is manual. The fix: pick a real authoring system on day one. React Email or MJML. Either works; both compound.

## Design Discipline: Brand Consistency Across Templates

Templates drift in look-and-feel over time. Build the discipline.

Help me set up email design consistency.

The structure:

1. Email design tokens

Define ONCE; use everywhere:

// emails/theme.ts
export const colors = {
  primary: '#0066CC',
  text: '#1A1A1A',
  textMuted: '#6B7280',
  background: '#FFFFFF',
  backgroundAlt: '#F5F5F5',
  border: '#E5E5E5',
};

export const fonts = {
  body: 'system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif',
  heading: 'system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif',
};

export const spacing = {
  xs: '4px', sm: '8px', md: '16px', lg: '24px', xl: '40px',
};

Each template imports from theme.ts.

2. Reusable layout components

// emails/components/EmailLayout.tsx
import { Html, Body, Container, Section, Img, Text, Hr } from '@react-email/components';

export function EmailLayout({ children, preheader }: { children: React.ReactNode; preheader: string }) {
  return (
    <Html>
      <head>
        <title>{preheader}</title>
      </head>
      <Body style={{ background: colors.backgroundAlt, fontFamily: fonts.body }}>
        <span style={{ display: 'none' }}>{preheader}</span>
        <Container style={{ background: colors.background, padding: spacing.lg }}>
          <Img src={`${BASE_URL}/logo.png`} width={120} alt="Acme" />
          <Section>{children}</Section>
          <Hr style={{ borderColor: colors.border, margin: `${spacing.xl} 0` }} />
          <Text style={{ color: colors.textMuted, fontSize: 12 }}>
            You''re receiving this because... <Link href="...">Unsubscribe</Link>
          </Text>
        </Container>
      </Body>
    </Html>
  );
}

Every email uses EmailLayout. Brand consistency for free.

3. Standard typography components

export function H1({ children }: { children: React.ReactNode }) {
  return <Text style={{ fontSize: 24, fontWeight: 600, color: colors.text }}>{children}</Text>;
}

export function P({ children }: { children: React.ReactNode }) {
  return <Text style={{ fontSize: 16, lineHeight: '24px', color: colors.text }}>{children}</Text>;
}

export function Button({ href, children }: { href: string; children: React.ReactNode }) {
  return (
    <table role="presentation"><tr><td>
      <a href={href} style={{
        background: colors.primary, color: 'white',
        padding: '12px 24px', borderRadius: 6,
        textDecoration: 'none', fontWeight: 500,
        display: 'inline-block',
      }}>
        {children}
      </a>
    </td></tr></table>
  );
}

Templates use <H1>, <P>, <Button> — never raw HTML.

4. The "preheader" rule

The preheader (preview text in inbox) is critical:

  • First 100 characters under subject line in inbox
  • Most templates skip → "View in browser" leaks
  • Always set explicitly

5. Light + dark mode

In 2026, most email clients support dark mode:

  • Mac Mail / Gmail / Outlook adjust colors
  • Test light + dark separately
  • Use prefers-color-scheme media query (limited support but improving)

6. The "no images of text" rule

Never put text in images — accessibility + dark-mode breaks.

Exception: logo.

7. The "alt text on every image" rule

Email clients block images by default for many users. Alt text saves the experience.

For my system:

  • Theme tokens
  • Layout component
  • Typography components

Output:

  1. The theme.ts file
  2. The EmailLayout component
  3. The component library

The biggest design-consistency mistake: **each email is its own snowflake.** Bob writes the welcome email; Alice writes the password reset; Carol writes the receipt. Three different button styles; three different paddings; three different footers. The fix: shared layout + components. Every template uses them. Custom is forbidden without team sign-off.

## Handle Dynamic Data Safely

Email templates take user data. Get the data-handling right.

Help me handle template data.

The principles:

1. Type-safe props

type WelcomeEmailProps = {
  user: {
    firstName: string;
    email: string;
  };
  workspace: {
    name: string;
    inviteLink: string;
  };
};

export function WelcomeEmail({ user, workspace }: WelcomeEmailProps) {
  return <EmailLayout preheader={`Welcome to ${workspace.name}`}>
    {/* ... */}
  </EmailLayout>;
}

TypeScript ensures you pass the right data.

2. Escape user-supplied content

User-generated content (names, message bodies) must be escaped:

  • React Email auto-escapes (safe by default)
  • Plain HTML / template-string approach: explicit escape

Don''t:

// XSS risk
const html = `<p>Welcome ${user.name}</p>`;

Do:

// React Email escapes for you
<P>Welcome {user.name}</P>

// Or in plain HTML, escape:
const html = `<p>Welcome ${escapeHtml(user.name)}</p>`;

3. Default values for missing data

Some users won''t have all fields:

const greeting = user.firstName ? `Hi ${user.firstName}` : 'Hi there';

Don''t render "Hi {{user.first_name}}" because of templating-error.

4. Localization (if applicable)

If you serve multiple languages (per internationalization-chat):

import { useTranslation } from 'react-i18next';

export function WelcomeEmail({ user, locale }: WelcomeEmailProps) {
  const { t } = useTranslation('emails', { lng: locale });
  return <P>{t('welcome.greeting', { name: user.firstName })}</P>;
}

5. URLs and tracking

Outbound links should:

  • Be HTTPS
  • Include UTM parameters for analytics
  • Use a redirect-tracker (Postmark / Customer.io provide; Resend handles)
const url = `https://app.example.com/dashboard?utm_source=email&utm_campaign=welcome`;

6. Personalization that won''t embarrass you

Don''t over-personalize:

  • "We noticed you''re from Cleveland" — feels stalker-y
  • "Hi [Name], here are 3 things you''ll love" — fine

Test with edge cases:

  • User with no first name (just email)
  • User with apostrophe in name (O''Brien)
  • User from another country
  • User with non-Latin name
  • User who blocked images

For my templates:

  • Type definitions
  • Escape strategy
  • Default values
  • Edge cases

Output:

  1. The prop typing
  2. The escape audit
  3. The edge-case testing

The biggest data-handling mistake: **failing to handle missing values.** Email goes out: "Welcome, {firstname}!" because the user signed up via SSO without first name. Looks broken. The fix: every dynamic value has a fallback; test missing-data cases explicitly.

## Multi-Client Rendering: The Outlook Tax

Email clients render differently. Test before shipping.

Help me test email rendering.

The pain:

Email clients vary wildly:

  • Gmail: modern; CSS support good
  • Apple Mail: modern; CSS support good
  • Outlook 2016+ (Windows): TERRIBLE; uses Word renderer; tables only
  • Outlook for Mac: better than Windows
  • Outlook.com: like Gmail
  • Yahoo: decent
  • iOS Mail: like Apple Mail
  • Android Gmail: depends on app

The compatibility realities:

Things that work everywhere:

  • Tables (<table> for layout)
  • Inline styles (<p style="color: red">)
  • Basic font choices
  • Simple links + buttons
  • Background colors (with table cells)

Things that work on most BUT NOT Outlook:

  • CSS Grid / Flexbox
  • <div> for layout
  • <style> in head (some Outlook versions strip)
  • CSS animations
  • Custom fonts (Outlook strips)
  • border-radius (mostly works; some clients ignore)

Things that NEVER work:

  • JavaScript
  • Forms (mostly; AMP for Email partial exception)
  • Video (use animated GIF instead, sparingly)
  • HTTP (must be HTTPS)

The "table-based layout" reality:

In 2026, even with React Email, you still use tables for layout in emails. React Email components compile to table HTML.

Don''t fight it. Author with React; let it compile to tables.

Testing tools:

Tool Cost Purpose
Litmus $99/mo Render preview across 90+ clients
Email on Acid $99/mo Similar to Litmus
Mailtrap $14/mo+ Catch test emails; preview rendering
Postmark dev preview Bundled Postmark accounts
Resend preview Bundled Resend accounts
react-email dev Free Live preview during dev
Browser preview Free Open the compiled HTML in browser

The "browser test" minimum:

Even without paid tools:

  • Browser: open compiled HTML
  • Send test to Gmail (browser + iOS app + Android app)
  • Send test to Outlook (web + desktop)
  • Send test to Apple Mail
  • Cover ~85% of recipients

The Outlook 2016+ specific advice:

If you support Outlook (and many B2B do):

  • Test in actual Outlook (not just Litmus screenshot)
  • Outlook uses Word for rendering — bizarre quirks
  • VML for round corners on buttons
  • Hide elements with conditional comments: <!--[if !mso]><!-->...<!--<![endif]-->
  • Use bulletproof button HTML (not just <a> styled)

For my testing:

  • Tools used
  • Client coverage
  • Outlook-specific testing

Output:

  1. The testing setup
  2. The client priority list
  3. The Outlook-specific patches

The biggest testing mistake: **not testing in Outlook.** Render looks great in Gmail; Outlook breaks the layout; 30% of B2B users see broken email. The fix: test in Outlook explicitly. Litmus / Email on Acid pay for themselves the first time you catch an Outlook bug.

## The Template Catalog: Manage Without Chaos

Templates accumulate. Without inventory, they sprawl.

Help me catalog email templates.

The structure:

Per template:

Field Example
Name welcome-email
Trigger User signs up
Audience All new users
Subject "Welcome to Acme!"
Owner Product / Marketing / Eng
Last reviewed 2026-04-30
Replaceable Yes / No

Categorize:

Category Examples
Transactional Receipt, invoice, password reset
Lifecycle Welcome, day-3, week-1
Notification Mention, comment reply, share
Digest Weekly summary, activity report
Marketing Newsletter, product launch
Account Email change, password change, billing failed

Storage convention:

emails/
  templates/
    transactional/
      receipt.tsx
      password-reset.tsx
    lifecycle/
      welcome.tsx
      day-3-tips.tsx
    notification/
      mention.tsx
      ...
  components/
    EmailLayout.tsx
    H1.tsx
    Button.tsx
    ...
  theme.ts
  send.ts

The single-source-of-truth rule:

Every email has ONE place where it''s defined.

Anti-pattern: same email defined in two places (transactional system + marketing automation tool). They drift. Pick one home.

Quarterly review:

  • Templates in catalog
  • Templates actually sent (last 90 days)
  • Templates with issues
  • Templates to deprecate

Some templates haven''t been sent in a year — kill them.

The "template owner" rule:

Every template has an owner:

  • Marketing / lifecycle: marketing
  • Transactional: product / engineering
  • Account: product / engineering

When something needs update: clear owner.

For my templates:

  • Catalog inventory
  • Categorization
  • Owners

Output:

  1. The catalog
  2. The categorization
  3. The owner assignments

The biggest catalog mistake: **no catalog.** A year in, you have 47 templates somewhere; nobody can list them; nobody owns them. The fix: catalog them all in one doc; categorize; assign owners. 30 minutes one time; clarity forever.

## Render Engine: Where Templates Compile and Send

How do templates actually get sent? Architecture matters.

Help me design the render-and-send pipeline.

The pipeline:

Trigger event → Pick template → Render with data → Send via provider → Track delivery

Step 1: Trigger event

  • User action (signup, purchase, comment)
  • Cron job (digest)
  • Manual send (admin tool)

Step 2: Pick template

async function sendEmail(name: string, data: any, recipient: string) {
  const template = await getTemplate(name);  // welcome | receipt | ...
  // ...
}

Step 3: Render

// Server-side render
import { render } from '@react-email/render';
import { WelcomeEmail } from './emails/welcome';

const html = await render(<WelcomeEmail user={user} />);
const text = await render(<WelcomeEmail user={user} />, { plainText: true });

Provide BOTH HTML and plaintext (some clients still use text version).

Step 4: Send via provider

Per email-providers:

// Resend example
import { Resend } from 'resend';

await resend.emails.send({
  from: 'Acme <noreply@acme.com>',
  to: recipient,
  subject: 'Welcome!',
  html,
  text,
  reply_to: 'support@acme.com',
  headers: {
    'X-Entity-Ref-ID': eventId,  // For tracking
  },
});

Step 5: Track

  • Provider webhooks (delivered / opened / clicked / bounced)
  • Per outbound-webhooks-chat
  • Update DB (sent_at, opened_at, etc.)

The async-vs-sync rule:

Sending is slow (200-1000ms). Don''t block user requests.

// Bad: blocks API
async function POST(req) {
  await db.users.create(...);
  await sendEmail('welcome', user);  // 500ms; blocks
  return Response.json({ ok: true });
}

// Good: async
async function POST(req) {
  await db.users.create(...);
  await queueEmail('welcome', user);  // queue for background send
  return Response.json({ ok: true });
}

Per cron-scheduled-tasks-chat: use queue (Inngest / Vercel Queues / etc.).

The retry pattern:

Email sends can fail (provider down, rate limit). Retry:

await sendEmailWithRetry({
  template: 'welcome',
  data: { user },
  retries: 3,
  backoff: 'exponential',
});

Provider SDKs often have built-in retry. Otherwise: queue → retry.

The deduplication pattern:

Avoid double-sending:

// Idempotency key
await sendEmail('receipt', {
  data: { invoice },
  idempotencyKey: `receipt-${invoice.id}`,
});

Some providers support; otherwise track sent in DB.

The dev / staging behavior:

In dev / staging, NEVER send to real users:

const recipient =
  process.env.NODE_ENV === 'production'
    ? user.email
    : process.env.DEV_TEST_EMAIL;  // your team email

Or use Mailtrap (catches test emails; doesn''t deliver).

For my pipeline:

  • Render approach
  • Send approach (sync vs async)
  • Retry / dedup
  • Dev safety

Output:

  1. The pipeline architecture
  2. The async / queue setup
  3. The dev-safety rules

The biggest pipeline mistake: **synchronous send in API request.** API takes 800ms because email send is included. User experience suffers. Or: dev environment accidentally sends to real users. The fix: queue all sends; never send sync; safety-check dev.

## Internationalization & Time Zones

If you serve multiple markets, plan for it.

Help me handle i18n + timezones.

The patterns:

1. Locale per user

Store user.locale (e.g., "en-US", "fr-FR", "ja-JP").

When sending, render in user''s locale:

<EmailLayout locale={user.locale}>
  <P>{t('welcome.greeting', { name: user.firstName }, user.locale)}</P>
</EmailLayout>

Per internationalization-chat.

2. Translations storage

JSON files:

locales/
  en-US/
    emails/welcome.json
  fr-FR/
    emails/welcome.json

Each language gets its own translation file. Translation keys consistent.

3. Time zone for timestamps

If email contains times:

  • Show in user''s timezone
  • Or show UTC with timezone label
<P>Your meeting is at {formatInTimezone(date, user.timezone)} ({user.timezone})</P>

4. Right-to-left (RTL) support

For Arabic / Hebrew users:

<html dir="rtl" lang="ar">

Layouts mostly mirror; some elements need explicit RTL handling.

5. Date formats

Different locales use different date formats:

  • US: 04/30/2026
  • EU: 30/04/2026
  • ISO: 2026-04-30

Use locale-aware formatting:

new Intl.DateTimeFormat(user.locale, { dateStyle: 'long' }).format(date);

6. Currency

Per currency-fx-handling-chat:

new Intl.NumberFormat(user.locale, {
  style: 'currency',
  currency: 'USD',
}).format(amount);

For my system:

  • Languages supported
  • Date / time / currency localization
  • Translation workflow

Output:

  1. The i18n setup
  2. The localized templates
  3. The translation workflow

The biggest i18n mistake: **English-only emails to non-English users.** International customer signs up; gets English welcome email; feels generic. The fix: at minimum, use Intl APIs for dates / numbers / currency. Full translation when you have international scale.

## Testing and Quality

Templates ship with bugs without testing. Build the discipline.

Help me test email templates.

The test types:

1. Snapshot tests

import { render } from '@react-email/render';
import { WelcomeEmail } from './emails/welcome';

test('welcome email renders', async () => {
  const html = await render(<WelcomeEmail user={{ firstName: 'Test' }} />);
  expect(html).toMatchSnapshot();
});

Catches unintended changes.

2. Accessibility tests

  • Alt text on images
  • Semantic HTML where possible
  • Color contrast OK
  • Readable in screen readers

Tools: Pa11y (CLI accessibility checker)

3. Visual regression

Tools: Litmus / Email on Acid render preview; or Percy for HTML pages

Compare current render to last-known-good.

4. Edge case tests

  • Long names ("This is a very long first name that overflows")
  • Empty / null fields
  • Names with apostrophes (O''Brien)
  • Unicode names (李明)
  • Long emails
  • Long URLs

Catch edge-case rendering bugs.

5. Subject line tests

Subject lines:

  • < 50 characters preferred (mobile)
  • No emoji-overload
  • No spam-trigger words
  • Personalization where appropriate

A/B test subject lines (per ab-testing-chat).

6. Spam-score check

Tools: Mail-Tester (email a unique address; get spam score)

Most providers (Postmark / Resend) auto-check.

Common triggers:

  • All caps
  • Excessive punctuation ("FREE!!!")
  • "Click here" without context
  • Image-heavy / text-light
  • Unsubscribe missing

7. Render-and-screenshot pre-deploy

CI step:

  • Render template to HTML
  • Screenshot in headless browser
  • Compare to baseline
  • Fail if different

For my system:

  • Test types
  • CI integration
  • Edge-case coverage

Output:

  1. The test plan
  2. The CI integration
  3. The edge-case fixtures

The biggest testing mistake: **shipping templates untested in production.** Customer reports broken email; you find a missing `</td>` tag; embarrassing. The fix: snapshot tests + visual regression in CI; edge-case fixtures; can''t merge if tests fail.

## Avoid Common Pitfalls

Recognizable failure patterns.

The email-template mistake checklist.

Mistake 1: Plain HTML strings with concat

  • XSS risk; unmaintainable
  • Fix: React Email or MJML

Mistake 2: No design tokens

  • Brand drift across templates
  • Fix: theme.ts + shared components

Mistake 3: Outlook untested

  • 30% of B2B users see broken
  • Fix: explicit Outlook testing

Mistake 4: Missing alt text / preheader

  • Image-blocked users see broken
  • Fix: discipline on every template

Mistake 5: Synchronous send in API

  • Slow API responses
  • Fix: queue / async

Mistake 6: No dev-safety

  • Test emails reach real users
  • Fix: env-based recipient routing

Mistake 7: No retry on send failure

  • Lost emails when provider blips
  • Fix: retry with backoff

Mistake 8: Templates not in version control

  • Stored in marketing tool only
  • Fix: code-repo as source of truth

Mistake 9: No catalog

  • 47 templates; nobody knows what''s sent
  • Fix: catalog with owners

Mistake 10: Image-of-text design

  • Dark mode breaks; accessibility fails
  • Fix: real text, never image-of-text

The quality checklist:

  • Authoring tool picked (React Email / MJML)
  • Theme tokens + shared layout component
  • Type-safe props per template
  • Preheader on every template
  • Alt text on every image
  • Tested in 5+ clients including Outlook
  • Async send via queue
  • Retry + dedup
  • Dev-safety (no real emails in dev)
  • Catalog with owners
  • CI: snapshot + edge-case tests

For my templates:

  • Audit
  • Top 3 fixes

Output:

  1. Audit results
  2. Top 3 fixes
  3. The "v2 email infrastructure" plan

The single most-common mistake: **treating emails as one-off projects.** Every template is its own snowflake; brand drifts; testing skipped; bugs ship. The fix: email is infrastructure. Theme + components + tests + catalog. The discipline pays back constantly because emails are seen by every user, every day.

---

## What "Done" Looks Like

A working email-template system in 2026 has:

- Authoring tool picked (React Email default for React shops; MJML for non-React)
- Design tokens + shared layout components
- Type-safe template props
- Preheader + alt-text on every template
- Multi-client tested (Gmail / Outlook / Apple Mail / iOS / Android)
- Async send via queue with retry + dedup
- Dev-safety preventing real-user emails in dev
- Catalog of all templates with owners
- CI tests (snapshot, edge-case, visual regression)
- Quarterly review removing unused templates

The hidden cost of weak email-template infrastructure: **broken trust at the most personal touchpoint.** Email is one-on-one; broken email feels personal; customers notice. A welcome email that looks broken in Outlook tells the recipient "this company doesn''t care about details." Templates compound — invest once; benefit on every send. The opposite — bespoke per-template work — is permanent tax with constant brand drift.

## See Also

- [Email Deliverability](email-deliverability-chat.md) — getting emails through
- [Outbound Webhooks](outbound-webhooks-chat.md) — provider event tracking
- [Cron Jobs & Scheduled Tasks](cron-scheduled-tasks-chat.md) — scheduled sends
- [Internationalization](internationalization-chat.md) — localized templates
- [Currency & FX Handling](currency-fx-handling-chat.md) — money in receipts
- [In-App Notifications](in-app-notifications-chat.md) — adjacent / alternative channel
- [Mobile Push Notifications](mobile-push-notifications-chat.md) — adjacent channel
- [Onboarding Email Sequence](onboarding-email-sequence-chat.md) — lifecycle emails
- [Caching Strategies](caching-strategies-chat.md) — template caching
- [Performance Optimization](performance-optimization-chat.md) — async send
- [VibeReference: Email Providers](https://www.vibereference.com/backend-and-data/email-providers) — sending layer
- [VibeReference: Email Marketing Providers](https://www.vibereference.com/marketing-and-seo/email-marketing-providers) — marketing tools
- [VibeReference: Resend](https://www.vibereference.com/backend-and-data/resend) — Resend specifics
- [VibeReference: AWS SES](https://www.vibereference.com/backend-and-data/aws-ses) — SES specifics
- [LaunchWeek: Email Sequences](https://www.launchweek.com/2-content/email-sequences) — strategy / playbook

[⬅️ Day 6: Grow Overview](README.md)