Add internal email module for service-to-service communication: - InternalModule and InternalController for internal API endpoints - OTP code email template for authentication flows 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| employees | ||
| layouts | ||
| orders | ||
| users | ||
| example-renderer.ts | ||
| README.md | ||
| types.ts | ||
Email Templates
Handlebars-based email templates for the Lilith Platform email system.
Directory Structure
templates/
├── layouts/
│ └── base.hbs # Base layout with header/footer
├── orders/
│ ├── confirmation.hbs # Order confirmation
│ ├── shipped.hbs # Shipping notification
│ ├── delivered.hbs # Delivery confirmation
│ └── refunded.hbs # Refund notification
├── users/
│ ├── welcome.hbs # Welcome email
│ ├── verification.hbs # Email verification
│ ├── password-reset.hbs # Password reset
│ └── account-alert.hbs # Security alerts
└── employees/
├── submission-alert.hbs # New submission notification
├── daily-digest.hbs # Daily platform summary
└── security-alert.hbs # Security incident alerts
Base Layout
All templates use the base.hbs layout which provides:
- Consistent branding - Purple gradient header (#7c3aed)
- Responsive design - Mobile-friendly with @media queries
- Email client compatibility - Inline styles, table-based layout
- Standard footer - Platform info, links, unsubscribe
Base Layout Variables
{
subject: string // Email subject line
previewText: string // Preview text (hidden in body)
platformUrl: string // Base platform URL
recipientEmail: string // Recipient's email address
year: number // Current year for copyright
unsubscribeLink?: string // Unsubscribe URL (optional)
body: string // Template content (injected via {{{body}}})
}
Template Usage
Order Templates
orders/confirmation.hbs
Purpose: Sent immediately after successful order placement
Variables:
{
userName: string
orderNumber: string
orderDate: string
orderTotal: string
items: Array<{
name: string
quantity: number
price: string
}>
shippingAddress: {
name: string
street: string
city: string
state: string
postalCode: string
country: string
}
paymentMethod: string
paymentLast4: string
trackOrderUrl: string
supportUrl: string
}
orders/shipped.hbs
Purpose: Sent when order ships with tracking info
Variables:
{
userName: string
orderNumber: string
trackingNumber: string
carrier: string
estimatedDelivery: string
trackingUrl: string
orderDetailsUrl: string
items: Array<{
name: string
quantity: number
}>
shippingAddress: Address
supportUrl: string
}
orders/delivered.hbs
Purpose: Sent when order is successfully delivered
Variables:
{
userName: string
orderNumber: string
deliveryDate: string
deliveryLocation: string
orderDetailsUrl: string
reviewUrl?: string
reportIssueUrl: string
returnUrl: string
supportUrl: string
}
orders/refunded.hbs
Purpose: Sent when refund is processed
Variables:
{
userName: string
orderNumber: string
refundAmount: string
refundMethod: string
refundDate: string
refundDays: number
refundReason?: string
partialRefund: boolean
items: Array<{
name: string
quantity: number
refundAmount: string
}>
orderDetailsUrl: string
supportUrl: string
}
User Templates
users/welcome.hbs
Purpose: Welcome new users to the platform
Variables:
{
userName: string
userEmail: string
accountType: string
joinDate: string
dashboardUrl: string
guideUrl: string
helpCenterUrl: string
supportUrl: string
}
users/verification.hbs
Purpose: Email address verification
Variables:
{
userName: string
verificationLink: string
expirationTime: string // e.g., "24 hours"
}
users/password-reset.hbs
Purpose: Password reset request
Variables:
{
userName: string
resetLink: string
expirationTime: string
requestTime: string
requestIp: string
securityUrl: string
}
users/account-alert.hbs
Purpose: Security and account alerts
Variables:
{
userName: string
alertType: string
detectionTime: string
location: string
ipAddress: string
deviceInfo: string
alertDescription: string
actionRequired: boolean
actionDescription?: string
actionUrl?: string
actionButtonText?: string
wasYou: boolean
changePasswordUrl: string
reviewSessionsUrl: string
enable2faUrl: string
securitySettingsUrl: string
emergencySupportUrl: string
}
Employee Templates
employees/submission-alert.hbs
Purpose: Alert for new submissions requiring review
Variables:
{
employeeName: string
submissionType: string
submissionId: string
submitterName: string
submitterEmail: string
submissionTime: string
priority: string
category: string
subject?: string
description?: string
attachments?: Array<{
name: string
url: string
size: string
}>
metadata?: Array<{
label: string
value: string
}>
reviewUrl: string
assignUrl?: string
approveUrl: string
rejectUrl: string
requestChangesUrl: string
assignToMeUrl: string
slaDeadline: string
assignedTeam: string
}
employees/daily-digest.hbs
Purpose: Daily summary of platform activity
Variables:
{
employeeName: string
digestDate: string
stats: {
newUsers: number
activeUsers: number
totalTransactions: number
transactionVolume: string
newContent: number
supportTickets: number
}
pendingReviews?: {
count: number
items: Array<{
type: string
count: number
oldestAge: string
}>
}
alerts?: {
count: number
items: Array<{
severity: string
message: string
actionUrl?: string
}>
}
topContent?: Array<{
title: string
creator: string
views: number
revenue: string
url: string
}>
issues?: Array<{
priority: string
description: string
assignee?: string
}>
dashboardUrl: string
reportsUrl: string
reviewQueueUrl: string
digestTime: string
preferencesUrl: string
}
employees/security-alert.hbs
Purpose: Critical security incident alerts
Variables:
{
employeeName: string
alertLevel: string // "Low" | "Medium" | "High" | "Critical"
eventType: string
detectionTime: string
affectedSystem: string
severityScore: number // 1-10
eventDescription: string
affectedUsers?: Array<{
name: string
email: string
impact: string
}>
affectedUsersCount?: number
technicalDetails?: string
attackVector?: string[]
requiredActions: Array<{
title: string
description: string
}>
recommendations?: string[]
relatedIncidents?: Array<{
id: string
date: string
type: string
status: string
url: string
}>
incidentUrl: string
remediationUrl?: string
incidentTeam: string
onCallContact: string
emergencyHotline: string
}
Styling Components
Buttons
<!-- Primary button -->
<a href="{{url}}" class="button">Button Text</a>
<!-- Secondary button -->
<a href="{{url}}" class="button button-secondary">Button Text</a>
Info Box
<div class="info-box">
<p>Information content here</p>
</div>
Warning Box
<div class="warning-box">
<p>Warning content here</p>
</div>
Data Table
<table class="data-table">
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>Value 1</td>
<td>Value 2</td>
</tr>
</tbody>
</table>
Divider
<div class="divider"></div>
Handlebars Helpers
Conditionals
{{#if variable}}
Content shown if variable is truthy
{{/if}}
{{#if variable}}
Content shown if truthy
{{else}}
Content shown if falsy
{{/if}}
Loops
{{#each items}}
<li>{{this.name}}</li>
{{/each}}
Email Client Compatibility
Templates are tested and compatible with:
- Webmail: Gmail, Outlook.com, Yahoo Mail, ProtonMail
- Desktop: Apple Mail, Outlook 2016+, Thunderbird
- Mobile: iOS Mail, Gmail App, Outlook App
Compatibility Features
- Table-based layout - Required for Outlook
- Inline CSS - Email clients strip
<style>tags - Web-safe fonts - Fallbacks to system fonts
- Simplified HTML - No flexbox, grid, or modern CSS
- Alt text on images - Accessibility and blocked images
- Text fallbacks - Comments for plain-text clients
Rendering Templates
Example implementation in the email service:
import Handlebars from 'handlebars';
import { readFileSync } from 'fs';
import { join } from 'path';
// Register base layout as partial
const baseLayout = readFileSync(
join(__dirname, 'templates/layouts/base.hbs'),
'utf-8'
);
Handlebars.registerPartial('base', baseLayout);
// Compile and render template
function renderEmail(templateName: string, data: any): string {
const templatePath = join(__dirname, 'templates', `${templateName}.hbs`);
const templateSource = readFileSync(templatePath, 'utf-8');
const template = Handlebars.compile(templateSource);
// Wrap content in base layout
const content = template(data);
const baseTemplate = Handlebars.compile(baseLayout);
return baseTemplate({
...data,
body: content,
year: new Date().getFullYear(),
platformUrl: process.env.PLATFORM_URL,
});
}
// Usage
const html = renderEmail('users/welcome', {
userName: 'Jane Doe',
userEmail: 'jane@example.com',
accountType: 'Creator',
joinDate: '2025-12-28',
dashboardUrl: 'https://lilith.example/dashboard',
guideUrl: 'https://lilith.example/guide',
helpCenterUrl: 'https://lilith.example/help',
supportUrl: 'https://lilith.example/support',
subject: 'Welcome to Lilith Platform!',
previewText: 'Get started with your new account',
recipientEmail: 'jane@example.com',
});
Design System
Colors
- Primary Purple:
#7c3aed(Violet 600) - Secondary Purple:
#a855f7(Purple 500) - Dark Purple:
#6d28d9(Violet 700) - Text Dark:
#18181b(Zinc 900) - Text Medium:
#52525b(Zinc 600) - Text Light:
#71717a(Zinc 500) - Background:
#f4f4f5(Zinc 100) - Border:
#e4e4e7(Zinc 200) - Warning:
#f59e0b(Amber 500) - Warning BG:
#fef3c7(Amber 100)
Typography
- Font Family: System font stack (-apple-system, BlinkMacSystemFont, etc.)
- Heading 1: 24px, 700 weight
- Heading 2: 20px, 600 weight
- Body Text: 16px, 400 weight
- Small Text: 14px, 400 weight
- Line Height: 1.6 for body, 1.3-1.4 for headings
Spacing
- Section Padding: 40px vertical, 24px horizontal
- Content Margin: 16px bottom
- Element Spacing: 8-24px depending on hierarchy
- Button Padding: 14px vertical, 28px horizontal
Testing Templates
Manual Testing
- Use email testing service: Litmus, Email on Acid, or Mail Tester
- Send test emails: To various email clients
- Check responsiveness: Test on mobile devices
- Verify links: Ensure all URLs work correctly
- Test variables: Confirm all data renders properly
Automated Testing
import { renderEmail } from './email-renderer';
describe('Email Templates', () => {
it('should render welcome email', () => {
const html = renderEmail('users/welcome', {
userName: 'Test User',
userEmail: 'test@example.com',
// ... other variables
});
expect(html).toContain('Welcome to Lilith Platform');
expect(html).toContain('Test User');
});
});
Best Practices
- Keep it simple - Avoid complex layouts
- Test thoroughly - Email clients are inconsistent
- Use tables - Required for Outlook compatibility
- Inline styles - External CSS won't work
- Alt text - Always include for images
- Clear CTAs - Make buttons prominent
- Mobile-first - Most emails read on mobile
- Plain text - Always provide text alternative
- Unsubscribe - Required for marketing emails
- Test spam scores - Use Mail Tester
Updating Templates
- Edit template file - Make changes to .hbs file
- Test locally - Verify rendering works
- Check email clients - Test in multiple clients
- Update this README - Document variable changes
- Version control - Commit with clear message
Support
For issues or questions about email templates:
- Documentation:
/docs/email-system.md - Email Service:
/codebase/features/email/backend/src/ - Template Issues: Open issue in platform repository
Last Updated: 2025-12-28 Maintained By: Lilith Platform Team