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 componentAvailable 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 configurationTemplate Creation Workflow
- Create Template Component: Build React email component using common layout
- Define Props Interface: Type-safe props for template customization
- Apply Theme Colors: Use consistent color scheme with template-specific accents
- Add to Mapping: Register template in
templateMapping.ts - Update Actions: Include template in Convex email actions
- 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 devAuthentication 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/Emailinstead 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 addressesgetRecipientEmail(): Handles test mode redirection for safe developmentcreateVerificationUrl(): Generates verification URLs with proper encodingcreateResetUrl(): 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 URLEnhanced Security Features
- Subdomain Configuration: Automatically configured with
mail.subdomain for better email deliverability - Test Mode Support: Development emails safely redirected to
delivered@resend.dev - Environment Validation: Comprehensive validation with helpful error messages
- 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
siteNameparameter from database instead of hardcoded "TinyKit Pro"
Performance Optimizations
- Unified Database Query: Single
getEmailConfigquery 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/Advanced Notification System
TinyKit Pro includes a comprehensive notification system that supports both in-app and email delivery with advanced admin management capabilities.
Mailing List System
TinyKit Pro includes a unified mailing list system with waitlist collection, newsletter subscriptions, exit-intent popups, and Resend Audiences integration.