react-email-templates

React Email Templates Skill

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "react-email-templates" with this command: npx skills add vanman2024/ai-dev-marketplace/vanman2024-ai-dev-marketplace-react-email-templates

React Email Templates Skill

Comprehensive patterns and templates for building modern, responsive email templates using React Email components and JSX, with preview server setup and Resend integration.

Use When

  • Building reusable email components with React JSX

  • Creating responsive email templates that work across clients

  • Setting up React Email preview servers for development

  • Integrating React Email with Resend for dynamic content

  • Implementing welcome, transactional, and marketing emails

  • Styling emails with Tailwind CSS via @react-email/components

  • Testing email layouts before sending

  • Creating component libraries for email templates

Core Concepts

What is React Email

React Email is a library for building responsive, maintainable emails using React components and JSX. It provides:

  • JSX Templates: Write email templates as React components

  • Built-in Components: Email-safe components (Container, Row, Column, Text, Image, etc.)

  • Styling: Tailwind CSS support with safe subset for email clients

  • Preview Server: Built-in development server to test email rendering

  • Type Safety: Full TypeScript support for email props

  • Framework Agnostic: Send emails with Resend, SendGrid, Nodemailer, etc.

Installation

npm install react-email @react-email/components

or

yarn add react-email @react-email/components

Package Structure

// Core React Email import { render } from 'react-email';

// Components import { Body, Button, Column, Container, Head, Hr, Html, Img, Link, Preview, Row, Section, Text, Font, Head as EmailHead, } from '@react-email/components';

Core Patterns

  1. Basic Email Component

Simple, responsive email template structure:

import { Body, Container, Head, Html, Preview, Section, Text } from '@react-email/components';

interface BasicEmailProps { userName: string; message: string; }

export const BasicEmail: React.FC<BasicEmailProps> = ({ userName, message }) => { return ( <Html> <Head /> <Preview>Welcome to our service, {userName}!</Preview> <Body style={main}> <Container style={container}> <Section> <Text style={heading}>Welcome, {userName}!</Text> <Text style={paragraph}>{message}</Text> </Section> </Container> </Body> </Html> ); };

const main = { backgroundColor: '#f6f9fc', fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif', };

const container = { backgroundColor: '#ffffff', margin: '0 auto', padding: '20px 0 48px', marginBottom: '64px', };

const heading = { fontSize: '32px', lineHeight: '1.3', fontWeight: '700', color: '#1f2937', };

const paragraph = { fontSize: '16px', lineHeight: '26px', color: '#525252', };

  1. Welcome Email Template

Complete welcome email with branding, CTA button, and footer:

import { Body, Button, Column, Container, Head, Hr, Html, Img, Link, Preview, Row, Section, Text, } from '@react-email/components';

interface WelcomeEmailProps { userName: string; userEmail: string; activationUrl: string; companyName?: string; }

export const WelcomeEmail: React.FC<WelcomeEmailProps> = ({ userName, userEmail, activationUrl, companyName = 'Our Company', }) => { return ( <Html> <Head> <Font fontFamily="Geist" fallbackFontFamily="Verdana" webFont={{ url: 'https://cdn.jsdelivr.net/npm/geist-font@1.0.0/dist/geist-mono.woff2', format: 'woff2', }} /> </Head> <Preview>Welcome to {companyName}, {userName}!</Preview> <Body style={main}> <Container style={container}> {/* Header with Logo */} <Section style={header}> <Row> <Column> <Img src={https://${process.env.VERCEL_URL}/logo.png} width="40" height="40" alt={companyName} /> </Column> <Column style={{ paddingLeft: '8px' }}> <Text style={headerText}>{companyName}</Text> </Column> </Row> </Section>

      {/* Main Content */}
      &#x3C;Section style={content}>
        &#x3C;Text style={heading}>Welcome to {companyName}!&#x3C;/Text>
        &#x3C;Text style={paragraph}>
          Hi {userName},
        &#x3C;/Text>
        &#x3C;Text style={paragraph}>
          Thank you for signing up. We're excited to have you on board. To get started, please verify your email address by clicking the button below.
        &#x3C;/Text>

        {/* CTA Button */}
        &#x3C;Section style={buttonContainer}>
          &#x3C;Button style={button} href={activationUrl}>
            Verify Email Address
          &#x3C;/Button>
        &#x3C;/Section>

        &#x3C;Text style={paragraph}>
          This link expires in 24 hours. If you didn't create this account, you can ignore this email.
        &#x3C;/Text>
      &#x3C;/Section>

      &#x3C;Hr style={hr} />

      {/* Footer */}
      &#x3C;Section style={footer}>
        &#x3C;Row>
          &#x3C;Column>
            &#x3C;Text style={footerText}>
              {companyName} Inc. | {userEmail}
            &#x3C;/Text>
            &#x3C;Text style={footerText}>
              &#x3C;Link href="https://example.com/unsubscribe" style={link}>
                Unsubscribe
              &#x3C;/Link>
              {' | '}
              &#x3C;Link href="https://example.com/preferences" style={link}>
                Preferences
              &#x3C;/Link>
            &#x3C;/Text>
          &#x3C;/Column>
        &#x3C;/Row>
      &#x3C;/Section>
    &#x3C;/Container>
  &#x3C;/Body>
&#x3C;/Html>

); };

// Styles const main = { backgroundColor: '#f6f9fc', fontFamily: 'Geist, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', };

const container = { backgroundColor: '#ffffff', margin: '0 auto', padding: '20px 0 48px', marginBottom: '64px', };

const header = { padding: '20px 0', borderBottom: '1px solid #e5e7eb', };

const headerText = { fontSize: '18px', fontWeight: '700', color: '#1f2937', };

const content = { padding: '32px 0', };

const heading = { fontSize: '28px', lineHeight: '1.3', fontWeight: '700', color: '#1f2937', marginBottom: '16px', };

const paragraph = { fontSize: '15px', lineHeight: '1.6', color: '#525252', marginBottom: '12px', };

const buttonContainer = { paddingTop: '16px', paddingBottom: '16px', };

const button = { backgroundColor: '#2563eb', borderRadius: '4px', color: '#ffffff', fontSize: '15px', fontWeight: '600', padding: '12px 20px', textDecoration: 'none', textAlign: 'center' as const, };

const hr = { borderColor: '#e5e7eb', margin: '0', };

const footer = { paddingTop: '24px', paddingBottom: '24px', borderTop: '1px solid #e5e7eb', };

const footerText = { fontSize: '12px', color: '#6b7280', margin: '0 0 4px 0', };

const link = { color: '#2563eb', textDecoration: 'underline', };

  1. Transactional Email - Order Confirmation

Order confirmation email with itemized details and status tracking:

import { Body, Button, Column, Container, Head, Html, Img, Link, Preview, Row, Section, Text, } from '@react-email/components';

interface OrderConfirmationProps { orderNumber: string; customerName: string; orderDate: string; items: Array<{ name: string; quantity: number; price: number; }>; subtotal: number; tax: number; shipping: number; total: number; trackingUrl: string; }

export const OrderConfirmation: React.FC<OrderConfirmationProps> = ({ orderNumber, customerName, orderDate, items, subtotal, tax, shipping, total, trackingUrl, }) => { return ( <Html> <Head /> <Preview>Order {orderNumber} confirmed</Preview> <Body style={main}> <Container style={container}> {/* Header */} <Section style={header}> <Text style={heading}>Order Confirmation</Text> <Text style={subHeading}>Order #{orderNumber}</Text> </Section>

      {/* Customer Info */}
      &#x3C;Section style={section}>
        &#x3C;Text style={sectionHeading}>Thank you, {customerName}!&#x3C;/Text>
        &#x3C;Text style={paragraph}>
          Your order has been received and will be processed shortly.
        &#x3C;/Text>
        &#x3C;Text style={paragraph}>
          &#x3C;strong>Order Date:&#x3C;/strong> {orderDate}
        &#x3C;/Text>
      &#x3C;/Section>

      {/* Order Items */}
      &#x3C;Section style={section}>
        &#x3C;Text style={sectionHeading}>Order Items&#x3C;/Text>
        &#x3C;table style={table}>
          &#x3C;tbody>
            {items.map((item, idx) => (
              &#x3C;tr key={idx}>
                &#x3C;td style={tableCell}>{item.name}&#x3C;/td>
                &#x3C;td style={{ ...tableCell, textAlign: 'center' }}>{item.quantity}&#x3C;/td>
                &#x3C;td style={{ ...tableCell, textAlign: 'right' }}>
                  ${(item.price * item.quantity).toFixed(2)}
                &#x3C;/td>
              &#x3C;/tr>
            ))}
            &#x3C;tr>
              &#x3C;td colSpan={2} style={tableCellRight}>
                &#x3C;strong>Subtotal:&#x3C;/strong>
              &#x3C;/td>
              &#x3C;td style={tableCellRight}>${subtotal.toFixed(2)}&#x3C;/td>
            &#x3C;/tr>
            &#x3C;tr>
              &#x3C;td colSpan={2} style={tableCellRight}>
                &#x3C;strong>Tax:&#x3C;/strong>
              &#x3C;/td>
              &#x3C;td style={tableCellRight}>${tax.toFixed(2)}&#x3C;/td>
            &#x3C;/tr>
            &#x3C;tr>
              &#x3C;td colSpan={2} style={tableCellRight}>
                &#x3C;strong>Shipping:&#x3C;/strong>
              &#x3C;/td>
              &#x3C;td style={tableCellRight}>${shipping.toFixed(2)}&#x3C;/td>
            &#x3C;/tr>
            &#x3C;tr style={totalRow}>
              &#x3C;td colSpan={2} style={{ ...tableCellRight, color: '#ffffff' }}>
                &#x3C;strong>Total:&#x3C;/strong>
              &#x3C;/td>
              &#x3C;td style={{ ...tableCellRight, color: '#ffffff' }}>
                &#x3C;strong>${total.toFixed(2)}&#x3C;/strong>
              &#x3C;/td>
            &#x3C;/tr>
          &#x3C;/tbody>
        &#x3C;/table>
      &#x3C;/Section>

      {/* Tracking */}
      &#x3C;Section style={section}>
        &#x3C;Button style={button} href={trackingUrl}>
          Track Your Order
        &#x3C;/Button>
      &#x3C;/Section>

      {/* Footer */}
      &#x3C;Section style={footer}>
        &#x3C;Text style={footerText}>
          Questions? Contact us at support@example.com
        &#x3C;/Text>
      &#x3C;/Section>
    &#x3C;/Container>
  &#x3C;/Body>
&#x3C;/Html>

); };

// Styles const main = { backgroundColor: '#f6f9fc', fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', };

const container = { backgroundColor: '#ffffff', margin: '0 auto', padding: '20px 0 48px', marginBottom: '64px', };

const header = { padding: '20px 24px', backgroundColor: '#f3f4f6', borderBottom: '1px solid #e5e7eb', };

const heading = { fontSize: '24px', fontWeight: '700', color: '#1f2937', margin: '0 0 4px 0', };

const subHeading = { fontSize: '14px', color: '#6b7280', margin: '0', };

const section = { padding: '24px', borderBottom: '1px solid #e5e7eb', };

const sectionHeading = { fontSize: '16px', fontWeight: '600', color: '#1f2937', marginBottom: '12px', };

const paragraph = { fontSize: '14px', lineHeight: '1.5', color: '#525252', margin: '0 0 8px 0', };

const table = { width: '100%', borderCollapse: 'collapse' as const, };

const tableCell = { padding: '12px', borderBottom: '1px solid #e5e7eb', fontSize: '14px', color: '#525252', };

const tableCellRight = { ...tableCell, textAlign: 'right' as const, };

const totalRow = { backgroundColor: '#2563eb', };

const button = { backgroundColor: '#2563eb', borderRadius: '4px', color: '#ffffff', fontSize: '15px', fontWeight: '600', padding: '12px 20px', textDecoration: 'none', textAlign: 'center' as const, display: 'block' as const, width: 'fit-content', };

const footer = { padding: '24px', textAlign: 'center' as const, };

const footerText = { fontSize: '12px', color: '#6b7280', };

  1. Password Reset Email

Secure password reset flow with time-limited link:

import { Body, Button, Container, Head, Html, Preview, Section, Text } from '@react-email/components';

interface PasswordResetProps { userName: string; resetUrl: string; expiresIn: string; // e.g., "24 hours" }

export const PasswordReset: React.FC<PasswordResetProps> = ({ userName, resetUrl, expiresIn, }) => { return ( <Html> <Head /> <Preview>Reset your password</Preview> <Body style={main}> <Container style={container}> <Section style={content}> <Text style={heading}>Password Reset Request</Text> <Text style={paragraph}> Hi {userName}, </Text> <Text style={paragraph}> We received a request to reset the password associated with your account. Click the button below to reset it. </Text>

        &#x3C;Section style={buttonContainer}>
          &#x3C;Button style={button} href={resetUrl}>
            Reset Password
          &#x3C;/Button>
        &#x3C;/Section>

        &#x3C;Text style={warningText}>
          This link expires in {expiresIn}. If you didn't request this, you can ignore this email.
        &#x3C;/Text>

        &#x3C;Text style={paragraph}>
          For security reasons, never share this link with anyone.
        &#x3C;/Text>
      &#x3C;/Section>
    &#x3C;/Container>
  &#x3C;/Body>
&#x3C;/Html>

); };

const main = { backgroundColor: '#f6f9fc', fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', };

const container = { backgroundColor: '#ffffff', margin: '0 auto', padding: '40px 20px', };

const content = { padding: '20px', };

const heading = { fontSize: '24px', fontWeight: '700', color: '#1f2937', marginBottom: '20px', };

const paragraph = { fontSize: '15px', lineHeight: '1.6', color: '#525252', marginBottom: '16px', };

const buttonContainer = { paddingTop: '20px', paddingBottom: '20px', };

const button = { backgroundColor: '#dc2626', borderRadius: '4px', color: '#ffffff', fontSize: '15px', fontWeight: '600', padding: '12px 24px', textDecoration: 'none', };

const warningText = { fontSize: '13px', color: '#d97706', fontStyle: 'italic', marginBottom: '16px', };

  1. Marketing Email - Newsletter

Newsletter template with featured content, sections, and unsubscribe:

import { Body, Column, Container, Head, Html, Img, Link, Preview, Row, Section, Text, } from '@react-email/components';

interface NewsletterProps { recipientName: string; featuredTitle: string; featuredImage: string; featuredUrl: string; articles: Array<{ title: string; excerpt: string; url: string; image?: string; }>; unsubscribeUrl: string; }

export const Newsletter: React.FC<NewsletterProps> = ({ recipientName, featuredTitle, featuredImage, featuredUrl, articles, unsubscribeUrl, }) => { return ( <Html> <Head /> <Preview>Latest from our community</Preview> <Body style={main}> <Container style={container}> {/* Header */} <Section style={header}> <Text style={headerTitle}>Our Weekly Newsletter</Text> </Section>

      {/* Greeting */}
      &#x3C;Section style={content}>
        &#x3C;Text style={greeting}>Hi {recipientName},&#x3C;/Text>
        &#x3C;Text style={paragraph}>
          Here's what's happening in our community this week.
        &#x3C;/Text>
      &#x3C;/Section>

      {/* Featured Article */}
      &#x3C;Section style={featured}>
        &#x3C;Img src={featuredImage} width="100%" height="auto" alt={featuredTitle} />
        &#x3C;Section style={featuredContent}>
          &#x3C;Text style={featuredTitle}>{featuredTitle}&#x3C;/Text>
          &#x3C;Link href={featuredUrl} style={link}>
            Read More →
          &#x3C;/Link>
        &#x3C;/Section>
      &#x3C;/Section>

      {/* Articles Grid */}
      &#x3C;Section style={articlesSection}>
        {articles.map((article, idx) => (
          &#x3C;Row key={idx}>
            &#x3C;Column style={articleColumn}>
              {article.image &#x26;&#x26; (
                &#x3C;Img src={article.image} width="100%" height="auto" alt={article.title} />
              )}
              &#x3C;Text style={articleTitle}>{article.title}&#x3C;/Text>
              &#x3C;Text style={articleExcerpt}>{article.excerpt}&#x3C;/Text>
              &#x3C;Link href={article.url} style={link}>
                Read More →
              &#x3C;/Link>
            &#x3C;/Column>
          &#x3C;/Row>
        ))}
      &#x3C;/Section>

      {/* Footer */}
      &#x3C;Section style={footer}>
        &#x3C;Text style={footerText}>
          You're receiving this because you're subscribed to our newsletter.
        &#x3C;/Text>
        &#x3C;Text style={footerText}>
          &#x3C;Link href={unsubscribeUrl} style={link}>
            Unsubscribe
          &#x3C;/Link>
        &#x3C;/Text>
      &#x3C;/Section>
    &#x3C;/Container>
  &#x3C;/Body>
&#x3C;/Html>

); };

const main = { backgroundColor: '#f9fafb', fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', };

const container = { backgroundColor: '#ffffff', margin: '0 auto', padding: '20px 0', marginBottom: '64px', };

const header = { backgroundColor: '#1f2937', color: '#ffffff', padding: '32px 20px', textAlign: 'center' as const, };

const headerTitle = { fontSize: '28px', fontWeight: '700', margin: '0', color: '#ffffff', };

const content = { padding: '20px', };

const greeting = { fontSize: '18px', fontWeight: '600', color: '#1f2937', marginBottom: '12px', };

const paragraph = { fontSize: '15px', lineHeight: '1.6', color: '#525252', };

const featured = { margin: '20px 0', };

const featuredContent = { padding: '20px', backgroundColor: '#f3f4f6', };

const featuredTitle = { fontSize: '20px', fontWeight: '700', color: '#1f2937', marginBottom: '12px', };

const articlesSection = { padding: '20px', };

const articleColumn = { padding: '12px', borderRight: '1px solid #e5e7eb', };

const articleTitle = { fontSize: '16px', fontWeight: '600', color: '#1f2937', marginTop: '12px', marginBottom: '8px', };

const articleExcerpt = { fontSize: '14px', lineHeight: '1.5', color: '#6b7280', marginBottom: '12px', };

const link = { color: '#2563eb', textDecoration: 'none', fontWeight: '600', };

const footer = { backgroundColor: '#f9fafb', padding: '24px 20px', textAlign: 'center' as const, borderTop: '1px solid #e5e7eb', };

const footerText = { fontSize: '12px', color: '#6b7280', margin: '0 0 8px 0', };

Preview Server Setup

Development Server

Create a preview server for testing email templates:

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

async function main() { const emailHtml = render( <WelcomeEmail userName="John Doe" userEmail="john@example.com" activationUrl="https://example.com/activate/abc123" companyName="Example Co" />, );

console.log(emailHtml); }

main().catch(console.error);

Resend Integration

// Send email with React Email and Resend import { render } from 'react-email'; import { Resend } from 'resend'; import { WelcomeEmail } from './emails/welcome';

const resend = new Resend('your_resend_key_here');

async function sendWelcomeEmail(userName: string, userEmail: string) { const html = render( <WelcomeEmail userName={userName} userEmail={userEmail} activationUrl={https://app.example.com/activate/${generateToken()}} companyName="Your Company" />, );

const { data, error } = await resend.emails.send({ from: 'onboarding@example.com', to: userEmail, subject: Welcome to Your Company, ${userName}!, html: html, });

if (error) { console.error('Failed to send email:', error); return null; }

return data; }

Responsive Design Patterns

Mobile-First Approach

import { Container, Section, Column, Row } from '@react-email/components';

// Responsive container const ResponsiveSection = () => ( <Section> <Row> <Column style={{ width: '100%', maxWidth: '600px' }}> {/* Content scales on mobile */} </Column> </Row> </Section> );

// Key CSS properties for email-safe styling const responsiveStyles = { // Use pixel values or percentages width: '100%', maxWidth: '600px',

// Safe font stacks fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',

// Avoid absolute positioning margin: '0 auto', padding: '20px',

// Safe colors (avoid rgba for older clients) backgroundColor: '#ffffff', color: '#1f2937', };

Best Practices

Component Organization

// emails/components/Header.tsx export const Header: React.FC<{ title: string }> = ({ title }) => ( <Section style={headerStyle}> <Text style={heading}>{title}</Text> </Section> );

// emails/components/Footer.tsx export const Footer: React.FC = () => ( <Section style={footerStyle}> <Text style={footerText}>© 2024 Company. All rights reserved.</Text> </Section> );

// emails/welcome.tsx import { Header } from './components/Header'; import { Footer } from './components/Footer';

export const WelcomeEmail = () => ( <Html> <Body> <Container> <Header title="Welcome!" /> {/* Content */} <Footer /> </Container> </Body> </Html> );

Email Testing

  • Test across major email clients: Gmail, Outlook, Apple Mail

  • Use Resend's preview feature to verify rendering

  • Always provide text fallback for images

  • Test on mobile and desktop viewports

  • Validate links and button functionality

  • Check for accessibility (alt text, contrast ratios)

Performance Tips

  • Minimize inline CSS

  • Use safe color values (#hex)

  • Optimize images (JPEG for photos, PNG for graphics)

  • Keep emails under 25MB total

  • Use base64 only for small images

  • Avoid JavaScript (emails don't support it)

Security Best Practices

  • Never embed secrets in email HTML

  • Validate all dynamic content

  • Use HTTPS for all links

  • Implement authentication for preview URLs

  • Sanitize user-generated content

  • Use environment variables for API keys

Examples Directory Structure

  • welcome-email/

  • Complete welcome sequence templates

  • transactional/

  • Order confirmation, password reset, invoices

  • marketing/

  • Newsletters, promotional campaigns, digests

See individual example README files for complete implementation details.

Related Skills

  • email-delivery - Sending emails with Resend API

  • email-validation - Email address and template validation

  • email-webhooks - Delivery events and bounce handling

Resources

  • React Email Documentation

  • React Email Components

  • Resend React Email Integration

  • Email Client CSS Support

  • MJML Email Framework - Alternative template approach

Security Notes

  • API keys must be stored in environment variables (never hardcoded)

  • Use RESEND_API_KEY from secure secret management

  • Sanitize all user input before rendering in emails

  • Validate preview URLs to prevent unauthorized access

  • Log email rendering errors for debugging

  • Test HTML sanitization for email content

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

document-parsers

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

stt-integration

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

model-routing-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

rag-implementation

No summary provided by upstream source.

Repository SourceNeeds Review