email-templates

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 "email-templates" with this command: npx skills add tejovanthn/rasikalife/tejovanthn-rasikalife-email-templates

Email Templates Skill

Transactional email design using React Email and integration with email providers like Resend or AWS SES.

Core Principles

  • Responsive Design: Emails work on all devices

  • Accessibility: Proper semantic HTML and alt text

  • Plain Text Fallback: Always include plain text version

  • Deliverability: Follow best practices to avoid spam

  • Testing: Preview emails before sending

Installation

React Email

npm install react-email @react-email/components

Email provider (choose one)

npm install resend # Recommended npm install @aws-sdk/client-ses

React Email Setup

  1. Create Email Templates Directory

emails/ ├── welcome.tsx ├── reset-password.tsx ├── verify-email.tsx ├── receipt.tsx └── components/ ├── layout.tsx └── button.tsx

  1. Base Layout Component

// emails/components/layout.tsx import { Html, Head, Preview, Body, Container, Section, Text, } from "@react-email/components"

interface LayoutProps { preview: string children: React.ReactNode }

export function EmailLayout({ preview, children }: LayoutProps) { return ( <Html> <Head /> <Preview>{preview}</Preview> <Body style={main}> <Container style={container}> {children} <Section style={footer}> <Text style={footerText}> © 2026 Your Company. All rights reserved. </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 footer = { color: "#8898aa", fontSize: "12px", lineHeight: "16px", marginTop: "32px", }

const footerText = { margin: "0", textAlign: "center" as const, }

  1. Reusable Button Component

// emails/components/button.tsx import { Button as ReactEmailButton } from "@react-email/components"

interface ButtonProps { href: string children: React.ReactNode }

export function Button({ href, children }: ButtonProps) { return ( <ReactEmailButton href={href} style={button}> {children} </ReactEmailButton> ) }

const button = { backgroundColor: "#5469d4", borderRadius: "4px", color: "#fff", fontSize: "16px", fontWeight: "bold", textDecoration: "none", textAlign: "center" as const, display: "block", padding: "12px 24px", }

Email Templates

Welcome Email

// emails/welcome.tsx import { Section, Heading, Text, } from "@react-email/components" import { EmailLayout } from "./components/layout" import { Button } from "./components/button"

interface WelcomeEmailProps { name: string dashboardUrl: string }

export default function WelcomeEmail({ name, dashboardUrl }: WelcomeEmailProps) { return ( <EmailLayout preview={Welcome to our platform, ${name}!}> <Section style={content}> <Heading style={heading}>Welcome aboard, {name}!</Heading>

    &#x3C;Text style={paragraph}>
      We're excited to have you on board. Your account has been successfully created.
    &#x3C;/Text>
    
    &#x3C;Text style={paragraph}>
      Here's what you can do next:
    &#x3C;/Text>
    
    &#x3C;ul style={list}>
      &#x3C;li>Complete your profile&#x3C;/li>
      &#x3C;li>Explore the dashboard&#x3C;/li>
      &#x3C;li>Invite your team members&#x3C;/li>
    &#x3C;/ul>
    
    &#x3C;Button href={dashboardUrl}>
      Go to Dashboard
    &#x3C;/Button>
    
    &#x3C;Text style={paragraph}>
      If you have any questions, feel free to reply to this email.
    &#x3C;/Text>
  &#x3C;/Section>
&#x3C;/EmailLayout>

) }

const content = { padding: "24px", }

const heading = { fontSize: "24px", lineHeight: "32px", fontWeight: "700", margin: "0 0 16px", }

const paragraph = { fontSize: "16px", lineHeight: "24px", margin: "0 0 16px", }

const list = { fontSize: "16px", lineHeight: "24px", marginBottom: "16px", }

Password Reset Email

// emails/reset-password.tsx import { Section, Heading, Text, Hr, } from "@react-email/components" import { EmailLayout } from "./components/layout" import { Button } from "./components/button"

interface ResetPasswordEmailProps { name: string resetUrl: string expiresIn: string }

export default function ResetPasswordEmail({ name, resetUrl, expiresIn, }: ResetPasswordEmailProps) { return ( <EmailLayout preview="Reset your password"> <Section style={content}> <Heading style={heading}>Reset your password</Heading>

    &#x3C;Text style={paragraph}>Hi {name},&#x3C;/Text>
    
    &#x3C;Text style={paragraph}>
      We received a request to reset your password. Click the button below to choose a new password.
    &#x3C;/Text>
    
    &#x3C;Button href={resetUrl}>
      Reset Password
    &#x3C;/Button>
    
    &#x3C;Text style={paragraph}>
      This link will expire in {expiresIn}.
    &#x3C;/Text>
    
    &#x3C;Hr style={hr} />
    
    &#x3C;Text style={small}>
      If you didn't request a password reset, you can safely ignore this email.
    &#x3C;/Text>
  &#x3C;/Section>
&#x3C;/EmailLayout>

) }

const content = { padding: "24px", }

const heading = { fontSize: "24px", lineHeight: "32px", fontWeight: "700", margin: "0 0 16px", }

const paragraph = { fontSize: "16px", lineHeight: "24px", margin: "0 0 16px", }

const hr = { borderColor: "#e6ebf1", margin: "20px 0", }

const small = { fontSize: "14px", lineHeight: "20px", color: "#6b7280", }

Receipt Email

// emails/receipt.tsx import { Section, Heading, Text, Hr, Row, Column, } from "@react-email/components" import { EmailLayout } from "./components/layout"

interface ReceiptEmailProps { name: string orderId: string date: string items: Array<{ name: string quantity: number price: number }> total: number }

export default function ReceiptEmail({ name, orderId, date, items, total, }: ReceiptEmailProps) { return ( <EmailLayout preview={Receipt for order ${orderId}}> <Section style={content}> <Heading style={heading}>Thanks for your order!</Heading>

    &#x3C;Text style={paragraph}>Hi {name},&#x3C;/Text>
    
    &#x3C;Text style={paragraph}>
      Your order has been confirmed. Here's a summary:
    &#x3C;/Text>
    
    &#x3C;Section style={orderInfo}>
      &#x3C;Text style={label}>Order ID: &#x3C;strong>{orderId}&#x3C;/strong>&#x3C;/Text>
      &#x3C;Text style={label}>Date: {date}&#x3C;/Text>
    &#x3C;/Section>
    
    &#x3C;Hr style={hr} />
    
    {items.map((item, index) => (
      &#x3C;Row key={index} style={itemRow}>
        &#x3C;Column>
          &#x3C;Text style={itemName}>{item.name}&#x3C;/Text>
          &#x3C;Text style={itemQuantity}>Qty: {item.quantity}&#x3C;/Text>
        &#x3C;/Column>
        &#x3C;Column style={itemPriceColumn}>
          &#x3C;Text style={itemPrice}>${item.price.toFixed(2)}&#x3C;/Text>
        &#x3C;/Column>
      &#x3C;/Row>
    ))}
    
    &#x3C;Hr style={hr} />
    
    &#x3C;Row style={totalRow}>
      &#x3C;Column>
        &#x3C;Text style={totalLabel}>Total&#x3C;/Text>
      &#x3C;/Column>
      &#x3C;Column style={totalPriceColumn}>
        &#x3C;Text style={totalPrice}>${total.toFixed(2)}&#x3C;/Text>
      &#x3C;/Column>
    &#x3C;/Row>
  &#x3C;/Section>
&#x3C;/EmailLayout>

) }

const content = { padding: "24px" } const heading = { fontSize: "24px", fontWeight: "700", margin: "0 0 16px" } const paragraph = { fontSize: "16px", margin: "0 0 16px" } const orderInfo = { backgroundColor: "#f6f9fc", padding: "16px", borderRadius: "4px", marginBottom: "16px" } const label = { fontSize: "14px", margin: "4px 0" } const hr = { borderColor: "#e6ebf1", margin: "20px 0" } const itemRow = { marginBottom: "12px" } const itemName = { fontSize: "16px", margin: "0" } const itemQuantity = { fontSize: "14px", color: "#6b7280", margin: "4px 0 0" } const itemPriceColumn = { textAlign: "right" as const } const itemPrice = { fontSize: "16px", margin: "0" } const totalRow = { marginTop: "8px" } const totalLabel = { fontSize: "18px", fontWeight: "700", margin: "0" } const totalPriceColumn = { textAlign: "right" as const } const totalPrice = { fontSize: "18px", fontWeight: "700", margin: "0" }

Sending Emails

Using Resend (Recommended)

// lib/email.server.ts import { Resend } from "resend" import { render } from "@react-email/render" import WelcomeEmail from "~/emails/welcome"

const resend = new Resend(process.env.RESEND_API_KEY)

export async function sendWelcomeEmail(to: string, name: string, dashboardUrl: string) { const html = render(<WelcomeEmail name={name} dashboardUrl={dashboardUrl} />)

await resend.emails.send({ from: "noreply@yourapp.com", to, subject: "Welcome to Your App!", html, }) }

// Alternative: Using Resend with React component directly export async function sendWelcomeEmailDirect(to: string, name: string, dashboardUrl: string) { await resend.emails.send({ from: "noreply@yourapp.com", to, subject: "Welcome to Your App!", react: <WelcomeEmail name={name} dashboardUrl={dashboardUrl} />, }) }

Using AWS SES

// lib/email.server.ts import { SESClient, SendEmailCommand } from "@aws-sdk/client-ses" import { render } from "@react-email/render" import WelcomeEmail from "~/emails/welcome"

const ses = new SESClient({ region: "us-east-1" })

export async function sendWelcomeEmail(to: string, name: string, dashboardUrl: string) { const html = render(<WelcomeEmail name={name} dashboardUrl={dashboardUrl} />) const text = render(<WelcomeEmail name={name} dashboardUrl={dashboardUrl} />, { plainText: true, })

const command = new SendEmailCommand({ Source: "noreply@yourapp.com", Destination: { ToAddresses: [to] }, Message: { Subject: { Data: "Welcome to Your App!" }, Body: { Html: { Data: html }, Text: { Data: text }, }, }, })

await ses.send(command) }

SST Integration

// sst.config.ts import { Config } from "sst/constructs"

export default { stacks(app) { app.stack(function Email({ stack }) { // Option 1: Resend API key const RESEND_API_KEY = new Config.Secret(stack, "RESEND_API_KEY")

  // Option 2: SES (no additional config needed)
  // Lambda functions automatically get SES permissions
  
  new RemixSite(stack, "site", {
    bind: [RESEND_API_KEY],
  })
})

}, }

Email Best Practices

Deliverability

// 1. Verify sender domain // Add SPF, DKIM, DMARC records to your DNS

// 2. Use proper from address from: "Your Name <noreply@yourapp.com>"

// 3. Include unsubscribe link <Link href={unsubscribeUrl} style={unsubscribeLink}> Unsubscribe </Link>

// 4. Authenticate email domain // With Resend: verify domain in dashboard // With SES: verify domain and configure DKIM

Content Guidelines

// DO: Use plain, professional language subject: "Your order #12345 has shipped"

// DON'T: Use spammy language subject: "🔥 AMAZING DEAL!!! BUY NOW!!!"

// DO: Include clear CTAs <Button href={url}>View Order</Button>

// DON'T: Use too many links // Limit to 1-3 primary CTAs

// DO: Provide context "You're receiving this because you signed up for updates on [date]"

// DON'T: Send without context // Always explain why they're receiving the email

Accessibility

import { Img } from "@react-email/components"

// Always include alt text <Img src="https://yourapp.com/logo.png" alt="Your App Logo" width="150" height="50" />

// Use semantic HTML <Heading>Main Title</Heading> <Text>Paragraph content</Text>

// Ensure good color contrast const linkStyle = { color: "#0066cc", // Good contrast with white background textDecoration: "underline", }

// Use readable font sizes const text = { fontSize: "16px", // Minimum 14px lineHeight: "24px", // 1.5x font size }

Testing Emails

Development Preview

Start React Email dev server

npm run email:dev

package.json

{ "scripts": { "email:dev": "email dev" } }

Visit http://localhost:3000 to preview emails

Send Test Emails

// scripts/test-email.ts import { sendWelcomeEmail } from "./lib/email.server"

await sendWelcomeEmail( "test@example.com", "Test User", "https://app.yourapp.com/dashboard" )

console.log("Test email sent!")

Email Testing Tools

// Use Mailtrap for testing in development const resend = new Resend( process.env.NODE_ENV === "production" ? process.env.RESEND_API_KEY : process.env.MAILTRAP_API_KEY )

// Use Litmus or Email on Acid for rendering tests across clients

Advanced Patterns

Email with Attachments

await resend.emails.send({ from: "noreply@yourapp.com", to: email, subject: "Your Invoice", react: <InvoiceEmail />, attachments: [ { filename: "invoice.pdf", content: pdfBuffer, }, ], })

Scheduled Emails

// Using EventBridge with SST import { Cron } from "sst/constructs"

new Cron(stack, "DailySummary", { schedule: "cron(0 9 * * ? *)", // 9 AM daily job: "functions/send-daily-summary.handler", })

// functions/send-daily-summary.ts export async function handler() { const users = await getActiveUsers()

for (const user of users) { await sendDailySummaryEmail(user.email, user.name, user.stats) } }

Email Analytics

// Track opens and clicks with Resend await resend.emails.send({ from: "noreply@yourapp.com", to: email, subject: "Your Report", react: <ReportEmail />, tags: [ { name: "category", value: "report" }, { name: "user_id", value: userId }, ], })

// Query analytics const analytics = await resend.emails.get(emailId) console.log(analytics.opens, analytics.clicks)

Common Email Types

// Welcome series export const welcomeEmails = [ { delay: 0, template: "welcome", subject: "Welcome!" }, { delay: 1, template: "getting-started", subject: "Getting Started Guide" }, { delay: 3, template: "tips", subject: "Pro Tips for Success" }, ]

// Transactional

  • Welcome email
  • Email verification
  • Password reset
  • Receipt/invoice
  • Shipping notification
  • Account changes

// Engagement

  • Weekly summary
  • Achievement unlocked
  • Abandoned cart
  • Re-engagement
  • Product updates

Resources

  • React Email Documentation

  • Resend Documentation

  • AWS SES Best Practices

  • Email on Acid

  • Can I email - Email client support tables

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.

General

frontend-design

No summary provided by upstream source.

Repository SourceNeeds Review
General

zod-validation

No summary provided by upstream source.

Repository SourceNeeds Review
General

conform

No summary provided by upstream source.

Repository SourceNeeds Review
General

marketing-copy

No summary provided by upstream source.

Repository SourceNeeds Review