TinyKit Pro Docs

Email Template System

TinyKit Pro includes a comprehensive email template system built with React Email, providing consistent, professional email communications across all notific...

TinyKit Pro includes a comprehensive email template system built with React Email, providing consistent, professional email communications across all notification types.

Template Features

  • 📧 React Email Integration: Modern email templates built with React components
  • 🎨 Database-First Theming: Dynamic theme colors from database with Tailwind CSS integration
  • 📱 Responsive Design: Mobile-optimized emails with @react-email/tailwind
  • 🎭 Template Variety: 22+ specialized templates organized by feature category
  • 🔄 Type-Safe Integration: Full TypeScript integration with Convex notification system
  • 🎨 Semantic Color System: Uses CSS variables for consistent theme colors
  • Performance Optimized: Single database query per email (50% improvement) with unified email configuration
  • 🎛️ Admin Theme Control: Visual theme editor with real-time email preview and color customization
  • 🌈 Dynamic Branding: Site name and theme colors loaded from database
  • 📁 Feature-Based Organization: Templates organized into logical subdirectories

Template Organization

All email templates are organized into feature-based subdirectories for better maintainability:

emails/
├── auth/                 # Authentication & Security (Better Auth integration pending)
├── notifications/        # System Notifications
│   ├── GeneralNotificationEmail.tsx # General notifications and announcements
│   ├── FeatureUpdateEmail.tsx      # Feature release notes
│   └── NotificationEmail.tsx       # General notifications
├── billing/             # Subscription & Payments
│   ├── SubscriptionCreatedEmail.tsx    # New subscriptions
│   ├── SubscriptionUpdatedEmail.tsx    # Plan changes
│   ├── SubscriptionCanceledEmail.tsx   # Cancellation notices
│   └── BillingUpdateEmail.tsx          # Payment updates
├── organization/        # Team Management
│   ├── OrgInvitationEmail.tsx      # Team invitations
│   ├── OrgMemberJoinedEmail.tsx    # New member announcements
│   ├── RoleChangeEmail.tsx         # Role change notifications
│   ├── OwnershipTransferredEmail.tsx    # Organization ownership transferred (to previous owner)
│   └── OwnershipReceivedEmail.tsx       # Organization ownership received (to new owner)
├── onboarding/          # User Onboarding
│   ├── WelcomeMessageEmail.tsx     # Welcome emails
│   ├── UserInvitationEmail.tsx     # Site-wide user invitations
│   ├── WaitlistLaunchEmail.tsx     # Product launch notifications
└── common/              # Shared Components
    ├── Layout.tsx       # Main email layout with theming
    ├── Header.tsx       # Email header component
    └── Footer.tsx       # Email footer component

Available Email Templates

Core Communication Templates

GeneralNotificationEmail

  • Purpose: General notifications and system-wide announcements
  • Features: Prominent announcement styling, action buttons, urgency indicators
  • Use Cases: System updates, important announcements, policy changes

WelcomeMessageEmail

  • Purpose: User onboarding and team welcome messages
  • Features: Welcoming design, getting started guidance, feature highlights
  • Use Cases: New user registration, team member welcomes, onboarding flows

NotificationEmail

  • Purpose: General-purpose template for basic notifications
  • Features: Clean design, flexible content areas, call-to-action support
  • Use Cases: Generic notifications, alerts, general communications

Team Management Templates

TeamInvitationEmail

  • Purpose: Team invitation emails with role information and expiration dates
  • Features: Team branding, role explanations, secure invitation links
  • Use Cases: Team member invitations, role assignments, team onboarding

TeamMemberJoinedEmail

  • Purpose: Notifications when new members join teams
  • Features: Member introduction, team context, collaboration encouragement
  • Use Cases: New member announcements, team growth notifications

RoleChangeEmail

  • Purpose: Role update notifications with permission explanations
  • Features: Before/after role comparison, permission summaries, action guidance
  • Use Cases: Role promotions, permission updates, access changes

Billing & Subscription Templates

BillingUpdateEmail

  • Purpose: Payment method updates, invoice notifications, billing alerts
  • Features: Financial styling, secure payment links, billing summaries
  • Use Cases: Payment failures, method updates, invoice notifications

SubscriptionCreatedEmail

  • Purpose: Welcome emails for new subscribers with plan details
  • Features: Plan feature highlights, billing information, getting started guide
  • Use Cases: New subscriptions, plan activations, welcome sequences

SubscriptionUpdatedEmail

  • Purpose: Plan changes, upgrades, billing cycle modifications
  • Features: Plan comparison, proration explanations, change summaries
  • Use Cases: Plan upgrades, billing changes, subscription modifications

SubscriptionCanceledEmail

  • Purpose: Cancellation confirmations with reactivation options
  • Features: Cancellation confirmation, feedback requests, reactivation links
  • Use Cases: Subscription cancellations, downgrades, churn prevention

System & Security Templates

FeatureUpdateEmail

  • Purpose: Product updates, new features, release announcements
  • Features: Feature showcases, changelog highlights, adoption guidance
  • Use Cases: Product releases, feature announcements, update notifications

Special Purpose Templates

WaitlistLaunchEmail

  • Purpose: Product launch notifications for waitlist users
  • Features: Launch celebration, exclusive access, early adopter benefits
  • Use Cases: Product launches, beta releases, exclusive access notifications

Database-First Theme System

Theme Integration

All email templates use a unified database-driven theme system for consistent branding:

EmailLayout Component

Location: /emails/common/Layout.tsx

interface EmailLayoutProps {
  preview: string;                    // Email preview text
  headerTitle: string;                // Header title
  headerIcon?: string;                // Header emoji/icon
  recipientEmail: string;             // Recipient's email
  supportEmail?: string;              // Support contact email
  footerMessage?: string;             // Custom footer message
  themeColors?: ThemeColors;          // Database theme colors
  children: React.ReactNode;          // Template content
}

export function EmailLayout({
  themeColors,
  children,
  ...props
}: EmailLayoutProps) {
  const tailwindConfig = {
    theme: {
      extend: {
        colors: themeColors ? {
          // Dynamic colors from database
          primary: themeColors.primary,
          secondary: themeColors.secondary,
          accent: themeColors.accent,
          muted: themeColors.muted,
          destructive: themeColors.destructive,
          background: themeColors.background,
          foreground: themeColors.foreground,
          card: themeColors.card,
          border: themeColors.border,
          // Auto-generated foreground colors
          "primary-foreground": generateForegroundColor(themeColors.primary),
          "secondary-foreground": generateForegroundColor(themeColors.secondary),
          // ... additional semantic colors
        } : {
          // Fallback colors when database unavailable
          primary: "rgb(99 102 241)",
          secondary: "rgb(100 116 139)",
          // ... fallback values
        }
      }
    }
  };

  return (
    <Html>
      <Head />
      <Preview>{preview}</Preview>
      <Tailwind config={tailwindConfig}>
        <Body className="bg-background font-sans">
          <Container className="max-w-2xl mx-auto">
            <EmailHeader {...props} />
            {children}
            <EmailFooter {...props} />
          </Container>
        </Body>
      </Tailwind>
    </Html>
  );
}

Semantic Color System

The email template system uses semantic color names that automatically adapt to site branding:

Available Color Classes

Background Colors:

bg-primary          /* Primary brand color */
bg-primary/10       /* Primary with 10% opacity */
bg-primary/20       /* Primary with 20% opacity */
bg-secondary        /* Secondary theme color */
bg-accent          /* Accent color for highlights */
bg-muted           /* Subdued backgrounds */
bg-destructive     /* Error states and warnings */
bg-background      /* Main content background */
bg-card            /* Card and container backgrounds */

Text Colors:

text-foreground           /* Primary text color */
text-primary              /* Brand color text */
text-primary-foreground   /* Text on primary backgrounds */
text-secondary-foreground /* Secondary text color */
text-accent-foreground    /* Accent text color */
text-muted-foreground     /* Subdued text */
text-destructive          /* Error and warning text */
text-card-foreground      /* Text for card content */

Border Colors:

border-primary      /* Brand color borders */
border-secondary    /* Secondary borders */
border-accent       /* Accent borders */
border-border       /* Standard borders */
border-destructive  /* Error state borders */

Template Color Usage Examples

// Primary announcement section
<Section className="bg-primary/10 border-2 border-primary rounded-lg p-6">
  <Text className="text-primary text-xl font-bold">Important Update</Text>
  <Text className="text-primary text-base">Your announcement message</Text>
</Section>

// Warning/error section
<Section className="bg-destructive/10 border border-destructive rounded-lg p-4">
  <Text className="text-destructive font-bold">⚠️ Security Alert</Text>
  <Text className="text-destructive text-sm">Action required message</Text>
</Section>

// Subdued information section
<Section className="bg-muted border border-border rounded-lg p-4">
  <Text className="text-muted-foreground font-semibold">Additional Info</Text>
  <Text className="text-muted-foreground text-sm">Supporting details</Text>
</Section>

Template Development

Directory Structure

/emails/
├── common/
│   ├── Header.tsx              # Reusable header component
│   ├── Footer.tsx              # Reusable footer component
│   ├── Layout.tsx              # Main layout wrapper
│   └── index.ts                # Common component exports
├── GeneralNotificationEmail.tsx
├── BillingUpdateEmail.tsx
├── FeatureUpdateEmail.tsx
├── SubscriptionCreatedEmail.tsx
├── TeamInvitationEmail.tsx
├── WelcomeMessageEmail.tsx
├── WaitlistLaunchEmail.tsx
├── renderTemplate.ts           # Template rendering utilities
├── templateMapping.ts          # Type-to-template mapping
└── tsconfig.json              # TypeScript configuration

Template Creation Workflow

  1. Create Template Component: Build React email component using common layout
  2. Define Props Interface: Type-safe props for template customization
  3. Apply Theme Colors: Use consistent color scheme with template-specific accents
  4. Add to Mapping: Register template in templateMapping.ts
  5. Update Actions: Include template in Convex email actions
  6. Test Integration: Verify template works with notification system

Template Props Pattern

All templates follow a consistent props pattern:

interface BaseEmailProps {
  title: string; // Email title/subject
  message: string; // Main email content
  recipientEmail: string; // Recipient's email address
  actionUrl?: string; // Optional call-to-action link
  actionText?: string; // CTA button text
  supportEmail?: string; // Support contact email
  themeColors?: ThemeColors; // Database theme colors
}

// Templates extend base props with specific fields
interface TeamInvitationEmailProps extends BaseEmailProps {
  inviterName: string; // Who sent the invitation
  teamName: string; // Team being invited to
  role?: string; // Role being assigned
  invitationUrl: string; // Invitation acceptance link
  expiresAt?: string; // Invitation expiration
}

Creating New Templates

// Example: CustomNotificationEmail.tsx
import { EmailLayout } from "./common/Layout";

interface CustomNotificationEmailProps extends BaseEmailProps {
  customField: string;              // Template-specific field
}

export const CustomNotificationEmail = ({
  title,
  message,
  recipientEmail,
  customField,
  themeColors
}: CustomNotificationEmailProps) => {
  return (
    <EmailLayout
      preview={`${title} - Custom Notification`}
      headerTitle="Custom Notification"
      headerIcon="🔔"
      recipientEmail={recipientEmail}
      supportEmail="support@example.com"
      themeColors={themeColors}
    >
      <Section className="bg-card border border-border rounded-lg p-6">
        <Text className="text-card-foreground text-2xl font-bold mb-4">
          {title}
        </Text>
        <Text className="text-card-foreground text-base leading-6 mb-4">
          {message}
        </Text>
        <Section className="bg-primary/10 border border-primary rounded-lg p-4">
          <Text className="text-primary font-semibold">
            Custom Field: {customField}
          </Text>
        </Section>
      </Section>
    </EmailLayout>
  );
};

Integration with Convex

Email Actions System

Email templates integrate seamlessly with Convex backend functions following the three-tier access pattern:

Location: /convex/emails/internal/actions.tsx (Internal actions for backend-only operations)

Template Rendering

import { render } from "@react-email/render";
import WelcomeMessageEmail from "../../emails/WelcomeMessageEmail";

// Render React Email component to HTML
const renderEmailTemplate = async (templateType: string, props: any) => {
  let emailComponent;

  switch (templateType) {
    case "welcome_message":
      emailComponent = React.createElement(WelcomeMessageEmail, props);
      break;
    case "team_invitation":
      emailComponent = React.createElement(TeamInvitationEmail, props);
      break;
    // ... handle all template types
    default:
      emailComponent = React.createElement(NotificationEmail, props);
  }

  return await render(emailComponent);
};

// Send email with rendered template
const sendEmailWithTemplate = async (ctx, emailData) => {
  const html = await renderEmailTemplate(emailData.template, emailData.props);

  const emailId = await resend.sendEmail(ctx, {
    from: "TinyKit Pro <noreply@example.com>",
    to: emailData.recipient,
    subject: emailData.subject,
    html,
  });

  return emailId;
};

Type-Safe Template Selection

// Template mapping ensures type safety
const templateMap: Record<NotificationType, string> = {
  general_notification: "GeneralNotificationEmail",
  team_invitation: "TeamInvitationEmail",
  welcome_message: "WelcomeMessageEmail",
  billing_update: "BillingUpdateEmail",
  subscription_created: "SubscriptionCreatedEmail",
  subscription_updated: "SubscriptionUpdatedEmail",
  subscription_canceled: "SubscriptionCanceledEmail",
  feature_update: "FeatureUpdateEmail",
  role_change: "RoleChangeEmail",
  team_member_joined: "TeamMemberJoinedEmail",
};

Email Preview System

Admin Interface Preview

The admin interface includes a live email preview system:

Location: /src/app/admin/notifications/_components/EmailPreview.tsx

import { render } from "@react-email/render";

const EmailPreview = ({ notificationType, formData, themeColors }) => {
  const [emailHtml, setEmailHtml] = useState("");

  useEffect(() => {
    const renderEmail = async () => {
      const emailComponent = createEmailComponent(notificationType, {
        ...formData,
        themeColors
      });
      const html = await render(emailComponent);
      setEmailHtml(html);
    };
    renderEmail();
  }, [notificationType, formData, themeColors]);

  return (
    <div className="border rounded-lg overflow-hidden">
      <div className="bg-muted px-4 py-2 border-b">
        <Text className="text-sm font-medium">Email Preview</Text>
      </div>
      <iframe
        srcDoc={emailHtml}
        className="w-full min-h-96 border-0"
        title="Email Preview"
        sandbox="allow-same-origin"
      />
    </div>
  );
};

Development Preview

For template development, use the preview system:

# Render template for testing
cd emails && npx tsx renderTemplate.ts

# Start email development server (if using React Email dev tools)
npx email dev

Authentication Email Templates

Modern React Email Integration for Auth Flows

TinyKit Pro now uses @convex-dev/auth Email provider with React Email templates for both password reset and email verification, providing a consistent experience across all authentication flows.

Recent Improvements (✨ New)

  • ✅ React Email Templates: Both password reset and email verification now use proper React Email components
  • ✅ Consistent Styling: Authentication emails match the application's design system
  • ✅ Enhanced Security: Better validation, test mode support, and secure token handling
  • ✅ Environment Variable Validation: Comprehensive validation with helpful error messages
  • ✅ Subdomain Best Practices: Automatic mail subdomain configuration for better deliverability

Authentication Template Components

Email Verification: /emails/VerificationCodeEmail.tsx

  • Welcome messaging for new users
  • 8-digit verification codes with 20-minute expiration
  • Optional quick verification URLs
  • Consistent branding with theme colors

Password Reset: /emails/PasswordResetCodeEmail.tsx

  • Security-focused messaging and alerts
  • 8-digit reset codes with 20-minute expiration
  • Enhanced fraud prevention information
  • Optional reset URLs for convenience

Technical Architecture

  • Email Provider: Uses @convex-dev/auth/providers/Email instead of direct Resend provider
  • Template Rendering: React Email components with proper theme integration
  • Configuration: Unified helper functions in /convex/emails/helpers.ts
  • Test Mode: Automatic redirection to safe test addresses during development

Email Provider Configuration

Location: /convex/emails/ResendOTPPasswordReset.ts and /convex/emails/ResendOTPEmailVerification.ts

import { Email } from "@convex-dev/auth/providers/Email";
import { PasswordResetCodeEmail } from "../../emails/PasswordResetCodeEmail";
import { getEmailConfig, getRecipientEmail, createResetUrl } from "./helpers";

export const ResendOTPPasswordReset = Email({
  id: "resend-otp",
  apiKey: process.env.RESEND_API_KEY!,
  maxAge: 60 * 20, // 20 minutes

  async generateVerificationToken() {
    // Cryptographically secure 8-digit code generation
    const random: RandomReader = {
      read(bytes) {
        crypto.getRandomValues(bytes);
      },
    };
    return generateRandomString(random, "0123456789", 8);
  },

  async sendVerificationRequest({ identifier: email, provider, token }) {
    const resend = new ResendAPI(provider.apiKey);

    // Get validated email configuration using helper
    const config = getEmailConfig("password-reset");

    // Create reset URL and handle test mode
    const resetUrl = createResetUrl(config, email);
    const finalRecipientEmail = getRecipientEmail(email);

    await resend.emails.send({
      from: config.from, // "Support <support@mail.yourdomain.com>"
      to: [finalRecipientEmail],
      subject: "Reset your password",
      react: PasswordResetCodeEmail({
        code: token,
        expires: new Date(Date.now() + 20 * 60 * 1000),
        resetUrl: resetUrl || undefined,
      }),
    });
  },
});

Helper Functions for Email Configuration

The authentication emails use centralized configuration helpers in /convex/emails/helpers.ts:

  • getEmailConfig(): Validates environment variables and returns formatted email addresses
  • getRecipientEmail(): Handles test mode redirection for safe development
  • createVerificationUrl(): Generates verification URLs with proper encoding
  • createResetUrl(): Creates password reset URLs for quick access

Configuration Requirements

Environment Variables for Authentication Emails:

# Required in .env.local (frontend environment)
RESEND_API_KEY=re_your_api_key_here

# Required in Convex environment (backend)
RESEND_TEST_MODE=true                  # Redirect emails to test address in development

# Email configuration is now managed via database
# Configure through: Admin Panel → Site Settings → Email Configuration
# Settings: Support Email, Support Email Name, Resend Domain, Site URL

Enhanced Security Features

  1. Subdomain Configuration: Automatically configured with mail. subdomain for better email deliverability
  2. Test Mode Support: Development emails safely redirected to delivered@resend.dev
  3. Environment Validation: Comprehensive validation with helpful error messages
  4. Secure Token Generation: Cryptographically secure random number generation for verification codes

Best Practices

Design Guidelines

  • Consistent Branding: All React Email templates use semantic colors that adapt to site branding
  • Mobile-First: Templates optimized with Tailwind responsive utilities
  • Accessibility: Proper color contrast using semantic foreground/background pairs
  • Cross-Client Support: @react-email/tailwind ensures compatibility across email clients
  • Auth Context Awareness: Understand when React Email templates cannot be used

Theme System Guidelines

  • Semantic Colors: Always use semantic classes (bg-primary, text-foreground) instead of hardcoded colors
  • Color Consistency: Use color pairs (primary/primary-foreground) for proper contrast
  • Opacity Variants: Use opacity modifiers (bg-primary/10) for subtle backgrounds
  • Fallback Values: Include fallback colors in Tailwind config for when database is unavailable
  • Theme Integration: Pass themeColors prop to EmailLayout for database-driven theming
  • No Hardcoded Tailwind Colors: Eliminated all blue-50, amber-400, red-600 style hardcoded colors
  • Dynamic Site Branding: Use siteName parameter from database instead of hardcoded "TinyKit Pro"

Performance Optimizations

  • Unified Database Query: Single getEmailConfig query replaces multiple database calls
  • 50% Query Reduction: Reduced from 2 to 1 database call per email
  • Efficient Data Loading: Combined theme colors, site name, and settings in one query
  • Cached Configuration: EmailLayout optimized for consistent branding across all templates

Content Guidelines

  • Clear Subject Lines: Descriptive and action-oriented email subjects
  • Scannable Content: Use headings, bullet points, and visual hierarchy
  • Action-Oriented CTAs: Clear call-to-action buttons using semantic button colors
  • Professional Tone: Consistent brand voice across all communications

Technical Standards

  • No Hardcoded Colors: Eliminated all hardcoded hex, rgb, and hsl values
  • Semantic Class Usage: Use utility classes for colors, spacing, and typography
  • TypeScript Integration: Full type safety for props and rendering
  • Performance: @react-email/tailwind with pixelBasedPreset for optimal email rendering

Troubleshooting

Common Issues

Templates not rendering with theme colors

  • Solution: Ensure themeColors prop is passed to EmailLayout
  • Verify database has theme colors configured in site settings
  • Check Tailwind config properly extends theme colors

Email colors not matching site branding

  • Solution: Verify ThemeColors interface matches database schema
  • Check that site branding settings are properly configured
  • Ensure color conversion from OKLCH to hex is working

Templates showing fallback colors instead of theme colors

  • Solution: Check that themeColors prop is not null/undefined
  • Verify database connection and theme color query
  • Ensure fallback colors in Tailwind config are acceptable

Semantic classes not working in email clients

  • Solution: Verify @react-email/tailwind is properly configured
  • Check that pixelBasedPreset is included in Tailwind config
  • Test with different email clients for compatibility

Authentication emails not using theme colors

  • Solution: Ensure auth emails have access to theme configuration
  • Verify email configuration in admin panel ("Site Settings → Email Configuration")
  • Check that React Email templates are properly imported in auth providers
  • Authentication emails now use the same React Email system as other notifications

Debug Commands

# Test email template rendering with themes
cd emails && npx tsx renderTemplate.ts

# View email-related Convex logs
npx convex logs --tail | grep "email\|template\|theme"

# Check for TypeScript errors in email templates
cd emails && npx tsc --noEmit

# Search for hardcoded colors (should return no results)
grep -r "#[0-9a-fA-F]\{6\}" emails/
grep -r "rgb(" emails/
grep -r "hsl(" emails/

← Previous: Site Banners | ← Back to Features

On this page

Ship your startup faster. In minutes.

Get TinyKit Pro