Claude-skill-registry email-dev

Email template development with React Email and Tailwind CSS. Use when creating or modifying email templates, testing email rendering, or building email HTML from React components.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/email-dev" ~/.claude/skills/majiayu000-claude-skill-registry-email-dev && rm -rf "$T"
manifest: skills/data/email-dev/SKILL.md
source content

Email Template Development

This skill guides the development of email templates using React Email with Tailwind CSS.

When to use this skill

  • Creating new email templates
  • Modifying existing email templates
  • Testing email rendering in different clients
  • Debugging email template styling
  • Compiling React Email to production HTML

Quick Commands

make dev-emails    # Start React Email dev server (http://localhost:3001)
make build-emails  # Compile React Email to HTML with Jinja2 variables

Development Workflow

1. Start Development Server

make dev-emails

Opens React Email preview UI at http://localhost:3001:

  • Live preview of all templates
  • Mobile/desktop view toggle
  • Built-in Tailwind CSS support
  • Auto-reload on changes

2. Create or Edit Templates

Templates location:

backend/emails/templates/

Shared Components:

  • _BaseLayout.tsx
    : Main email layout wrapper with Tailwind support
  • _Button.tsx
    : Styled button component

Example Template:

import { Button, Html, Text, Tailwind } from '@react-email/components';
import { BaseLayout } from './_BaseLayout';

interface WelcomeEmailProps {
  userName: string;
  loginUrl: string;
}

export const WelcomeEmail = ({ userName, loginUrl }: WelcomeEmailProps) => (
  <BaseLayout previewText="Welcome to Arive!">
    <Text className="text-lg font-semibold text-foreground mb-4">
      Hello {userName}!
    </Text>
    <Text className="text-muted-foreground mb-6">
      Thanks for joining Arive. Get started by logging in:
    </Text>
    <Button href={loginUrl} className="bg-primary text-primary-foreground">
      Log In Now
    </Button>
  </BaseLayout>
);

WelcomeEmail.PreviewProps = {
  userName: "John Doe",
  loginUrl: "https://app.tryarive.com/login",
} as WelcomeEmailProps;

export default WelcomeEmail;

3. Use Tailwind CSS Classes

The email templates support Tailwind CSS, which gets compiled to inline styles:

<div className="bg-neutral-50 p-4 rounded-lg border border-neutral-200">
  <Text className="text-foreground font-semibold">Important Notice</Text>
  <Text className="text-muted-foreground text-sm">Details here...</Text>
</div>

Available Theme Colors:

  • text-foreground
    /
    bg-foreground
  • text-background
    /
    bg-background
  • text-primary
    /
    bg-primary
  • text-muted
    /
    bg-muted
  • text-muted-foreground
  • Full neutral gray scale:
    neutral-50
    through
    neutral-950

Config:

backend/emails/tailwind.config.ts

4. Add Jinja2 Variables

Props in React components become Jinja2 template variables:

React:

interface MyEmailProps {
  userName: string;
  confirmUrl: string;
}

export const MyEmail = ({ userName, confirmUrl }: MyEmailProps) => (
  <BaseLayout>
    <Text>Hello {userName}</Text>
    <Button href={confirmUrl}>Confirm</Button>
  </BaseLayout>
);

Compiled HTML:

<p>Hello {{ userName }}</p>
<a href="{{ confirmUrl }}">Confirm</a>

5. Register Template Variables

Edit

backend/emails/scripts/build.ts
:

const TEMPLATE_VARIABLES: Record<string, Record<string, string>> = {
  'WelcomeEmail': {
    userName: 'John Doe',
    loginUrl: 'https://app.tryarive.com/login',
  },
  'MyNewEmail': {
    userName: 'Test User',
    confirmUrl: 'https://app.tryarive.com/confirm/abc123',
  },
};

6. Build Production Templates

make build-emails

This compiles:

  • React Email components → HTML
  • Tailwind CSS classes → inline styles
  • Props → Jinja2 variables
  • Output:
    backend/templates/emails-react/*.html.jinja2

7. Use Template in Backend

Add method to

EmailService
in
backend/app/lib/email.py
:

async def send_welcome_email(
    self,
    to_email: str,
    user_name: str,
    login_url: str,
) -> None:
    """Send welcome email to new user."""
    await self._send_email(
        template_name="WelcomeEmail.html.jinja2",
        to_email=to_email,
        subject="Welcome to Arive!",
        template_vars={
            "userName": user_name,
            "loginUrl": login_url,
        },
    )

Call from route handler:

@post("/register")
async def register_user(
    data: RegisterRequest,
    email_service: EmailService,
) -> UserResponse:
    user = await create_user(data)
    await email_service.send_welcome_email(
        to_email=user.email,
        user_name=user.name,
        login_url=f"https://app.tryarive.com/login",
    )
    return user

Template Structure

backend/emails/
├── templates/           # React Email source (.tsx)
│   ├── _BaseLayout.tsx  # Shared layout component
│   ├── _Button.tsx      # Shared button component
│   ├── WelcomeEmail.tsx # Example template
│   └── MyEmail.tsx      # Your new template
├── scripts/
│   ├── build.ts         # Build script (React → HTML)
│   └── watch.ts         # Dev server script
├── tailwind.config.ts   # Tailwind CSS config
└── package.json         # npm dependencies

backend/templates/emails-react/  # Compiled output (generated)
├── WelcomeEmail.html.jinja2
└── MyEmail.html.jinja2

Design System Guidelines

Colors

Use semantic color names that match the frontend:

  • Foreground: Main text color (
    text-foreground
    )
  • Muted: Secondary text (
    text-muted-foreground
    )
  • Primary: Brand color for CTAs (
    bg-primary
    )
  • Neutral grays: Backgrounds and borders (
    bg-neutral-50
    ,
    border-neutral-200
    )

Typography

<Text className="text-2xl font-bold text-foreground">Heading</Text>
<Text className="text-base text-foreground">Body text</Text>
<Text className="text-sm text-muted-foreground">Caption</Text>

Spacing

<div className="p-6">           {/* Padding */}
<div className="mb-4">          {/* Margin bottom */}
<div className="space-y-4">     {/* Vertical spacing between children */}

Layout

<Container className="max-w-xl">  {/* Max width container */}
  <Section className="bg-neutral-50 rounded-lg p-6">
    {/* Content */}
  </Section>
</Container>

Testing Email Rendering

1. Preview in Dev Server

  • Check desktop and mobile views
  • Test all interactive elements
  • Verify spacing and alignment

2. Send Test Emails

# In backend shell or test script
from app.lib.email import EmailService

email_service = EmailService()
await email_service.send_welcome_email(
    to_email="your-email@example.com",
    user_name="Test User",
    login_url="https://app.tryarive.com/login",
)

3. Email Client Testing

Test in multiple email clients:

  • Gmail (web + mobile app)
  • Outlook (web + desktop)
  • Apple Mail (macOS + iOS)
  • Others as needed

Common Issues

Styles not applying

  • Tailwind not compiling: Run
    make build-emails
  • Inline styles missing: Check Tailwind config includes all classes
  • Email client stripping styles: Use supported CSS properties only

Variables not rendering

  • Jinja2 syntax errors: Check template output in
    backend/templates/emails-react/
  • Missing variables: Verify TEMPLATE_VARIABLES in
    build.ts
  • Type mismatches: Ensure props match template variables

Images not loading

  • Relative paths: Use absolute URLs for images
  • CORS issues: Ensure image hosting allows email embedding
  • Size: Optimize images for email (< 100KB recommended)

Best Practices

  1. Mobile-first: Design for mobile screens, test responsive behavior
  2. Inline styles: Tailwind automatically inlines, but verify after build
  3. Alt text: Always include alt text for images
  4. Preheader text: Set via
    previewText
    prop in BaseLayout
  5. CTA buttons: Make them prominent and tap-friendly (44px min height)
  6. Dark mode: Consider email client dark mode support
  7. Accessibility: Use semantic HTML and proper color contrast

Production Deployment

Before deploying:

  1. Run
    make build-emails
    to compile templates
  2. Commit compiled templates in
    backend/templates/emails-react/
  3. Templates are included in Docker image build
  4. No Node.js runtime needed in production

Backend serves templates via Litestar's JinjaTemplateEngine at runtime.