346 lines
8.1 KiB
Markdown
346 lines
8.1 KiB
Markdown
# Email Templates
|
|
|
|
The Email Templates feature provides a complete email template management system with variable substitution, versioning, and rich text editing. Create reusable email templates for campaigns, notifications, and communications.
|
|
|
|
## Overview
|
|
|
|
The Email Templates system consists of four integrated components:
|
|
|
|
1. **[Template System](template-system.md)** - Template CRUD and management
|
|
2. **[Editor](editor.md)** - Rich text editor with variable insertion
|
|
3. **[Variables](variables.md)** - Dynamic content placeholders
|
|
4. **[Versioning](versioning.md)** - Template version history
|
|
|
|
## Features
|
|
|
|
### Template Management
|
|
|
|
- Create/edit/delete templates
|
|
- Category organization
|
|
- Template types (campaign, notification, system)
|
|
- Published/draft status
|
|
- Search and filtering
|
|
- Clone templates
|
|
|
|
### Rich Text Editor
|
|
|
|
- WYSIWYG HTML editor
|
|
- Variable insertion menu
|
|
- Preview mode
|
|
- HTML source view
|
|
- Image upload (future)
|
|
- Link management
|
|
|
|
### Variable System
|
|
|
|
Dynamic placeholders:
|
|
|
|
- **User variables** - `{{user.name}}`, `{{user.email}}`
|
|
- **Campaign variables** - `{{campaign.name}}`, `{{campaign.description}}`
|
|
- **Representative variables** - `{{rep.name}}`, `{{rep.title}}`, `{{rep.email}}`
|
|
- **Custom variables** - Template-specific placeholders
|
|
- **System variables** - `{{site.name}}`, `{{current.date}}`
|
|
|
|
### Version History
|
|
|
|
- Auto-save on changes
|
|
- Version diff viewer
|
|
- Restore previous versions
|
|
- Change log
|
|
|
|
## User Flow
|
|
|
|
### Admin Experience
|
|
|
|
1. **Create Template** (`/app/email-templates`)
|
|
- Click "New Template"
|
|
- Enter name and category
|
|
- Set template type
|
|
- Save draft
|
|
|
|
2. **Edit Template** (`/app/email-templates/:id/edit`)
|
|
- Full-screen rich text editor
|
|
- Insert variables from dropdown
|
|
- Preview with sample data
|
|
- Save changes
|
|
|
|
3. **Use Template**
|
|
- Select template in campaign form
|
|
- Variables auto-populated from context
|
|
- Send email with processed template
|
|
|
|
4. **Manage Versions** (`/app/email-templates/:id/versions`)
|
|
- View version history
|
|
- Compare versions
|
|
- Restore previous version
|
|
|
|
## Architecture
|
|
|
|
### Backend Components
|
|
|
|
**Module:**
|
|
- `api/src/modules/email-templates/email-templates.routes.ts` - Template CRUD
|
|
- `api/src/modules/email-templates/email-templates.service.ts` - Business logic
|
|
- `api/src/modules/email-templates/email-templates.schemas.ts` - Zod validation
|
|
|
|
**Database Models:**
|
|
- `EmailTemplate` - Template definitions (name, content, variables)
|
|
- `EmailTemplateVersion` - Version history (future)
|
|
|
|
**Email Processing:**
|
|
- Variable substitution in `email.service.ts`
|
|
- Mustache-style templating: `{{variable}}`
|
|
- HTML escaping for security
|
|
|
|
### Frontend Components
|
|
|
|
**Admin Pages:**
|
|
- `admin/src/pages/EmailTemplatesPage.tsx` - Template management table
|
|
- `admin/src/pages/EmailTemplateEditorPage.tsx` - Full-screen editor
|
|
|
|
**Editor Components:**
|
|
- `admin/src/components/email-templates/TemplateEditor.tsx` - Rich text editor
|
|
- `admin/src/components/email-templates/VariableInserter.tsx` - Variable dropdown
|
|
|
|
## Configuration
|
|
|
|
### Template Types
|
|
|
|
- **campaign** - Campaign email templates
|
|
- **notification** - User notifications
|
|
- **system** - System emails (verification, password reset)
|
|
- **custom** - Custom templates
|
|
|
|
### Template Categories
|
|
|
|
- **Influence** - Campaign-related templates
|
|
- **Map** - Shift/canvass notifications
|
|
- **User** - User account emails
|
|
- **System** - Automated system emails
|
|
|
|
## Variable System
|
|
|
|
### Available Variables
|
|
|
|
**User Context:**
|
|
```
|
|
{{user.id}} # User ID
|
|
{{user.email}} # Email address
|
|
{{user.name}} # Full name
|
|
{{user.role}} # User role
|
|
```
|
|
|
|
**Campaign Context:**
|
|
```
|
|
{{campaign.id}} # Campaign ID
|
|
{{campaign.name}} # Campaign name
|
|
{{campaign.description}} # Description
|
|
{{campaign.emailTemplate}} # Email body
|
|
```
|
|
|
|
**Representative Context:**
|
|
```
|
|
{{rep.name}} # Representative name
|
|
{{rep.title}} # Title (MP, MLA, etc.)
|
|
{{rep.email}} # Email address
|
|
{{rep.phone}} # Phone number
|
|
{{rep.district}} # District name
|
|
```
|
|
|
|
**System Context:**
|
|
```
|
|
{{site.name}} # Site name
|
|
{{site.url}} # Site URL
|
|
{{current.date}} # Current date
|
|
{{current.year}} # Current year
|
|
```
|
|
|
|
### Variable Insertion
|
|
|
|
```typescript
|
|
// Insert variable at cursor position
|
|
editor.insertContent('{{user.name}}');
|
|
|
|
// Variable dropdown menu
|
|
<Select>
|
|
<Option value="{{user.name}}">User Name</Option>
|
|
<Option value="{{user.email}}">User Email</Option>
|
|
<Option value="{{rep.name}}">Representative Name</Option>
|
|
</Select>
|
|
```
|
|
|
|
### Variable Processing
|
|
|
|
Server-side processing in `email.service.ts`:
|
|
|
|
```typescript
|
|
function processTemplate(
|
|
template: string,
|
|
variables: Record<string, any>
|
|
): string {
|
|
let processed = template;
|
|
|
|
for (const [key, value] of Object.entries(variables)) {
|
|
const placeholder = `{{${key}}}`;
|
|
processed = processed.replace(
|
|
new RegExp(placeholder, 'g'),
|
|
escapeHtml(String(value))
|
|
);
|
|
}
|
|
|
|
return processed;
|
|
}
|
|
```
|
|
|
|
## Database Schema
|
|
|
|
### EmailTemplate Model
|
|
|
|
```prisma
|
|
model EmailTemplate {
|
|
id Int @id @default(autoincrement())
|
|
name String
|
|
subject String
|
|
body String @db.Text
|
|
category String?
|
|
type String @default("custom")
|
|
variables Json? # Available variables
|
|
published Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
```
|
|
|
|
## API Endpoints
|
|
|
|
### Admin Endpoints
|
|
|
|
```
|
|
GET /api/email-templates # List templates
|
|
POST /api/email-templates # Create template
|
|
GET /api/email-templates/:id # Get template
|
|
PATCH /api/email-templates/:id # Update template
|
|
DELETE /api/email-templates/:id # Delete template
|
|
POST /api/email-templates/:id/clone # Clone template
|
|
GET /api/email-templates/:id/preview # Preview with sample data
|
|
```
|
|
|
|
## Security
|
|
|
|
### HTML Escaping
|
|
|
|
All variable values are HTML-escaped to prevent XSS:
|
|
|
|
```typescript
|
|
import { escapeHtml } from '../utils/sanitize';
|
|
|
|
const safe = escapeHtml(userInput);
|
|
// Converts: < > & " ' to HTML entities
|
|
```
|
|
|
|
### Template Validation
|
|
|
|
- Subject line: 1-200 characters
|
|
- Body: Required, max 50,000 characters
|
|
- Variables: Valid JSON object
|
|
- Category: Predefined list
|
|
|
|
## Best Practices
|
|
|
|
### Template Design
|
|
|
|
- Clear subject lines (50-60 chars)
|
|
- Personalize with variables
|
|
- Mobile-responsive HTML
|
|
- Plain text alternative
|
|
- Unsubscribe link
|
|
- Branding consistency
|
|
|
|
### Variable Usage
|
|
|
|
- Document available variables
|
|
- Provide defaults for missing values
|
|
- Test with sample data
|
|
- Validate variable names
|
|
|
|
### Version Management
|
|
|
|
- Meaningful version names
|
|
- Document changes
|
|
- Test before publishing
|
|
- Keep version history
|
|
|
|
## Desktop-Only Editor
|
|
|
|
Email template editor requires desktop browser:
|
|
|
|
```typescript
|
|
const screens = Grid.useBreakpoint();
|
|
const isMobile = !screens.md;
|
|
|
|
if (isMobile) {
|
|
return (
|
|
<Alert
|
|
message="Desktop Required"
|
|
description="Email editor requires desktop browser"
|
|
type="warning"
|
|
/>
|
|
);
|
|
}
|
|
```
|
|
|
|
## Integration Points
|
|
|
|
### Campaign Emails
|
|
|
|
Campaign emails use templates:
|
|
|
|
```typescript
|
|
// Select template in campaign form
|
|
<Select>
|
|
{templates.map(t => (
|
|
<Option value={t.id}>{t.name}</Option>
|
|
))}
|
|
</Select>
|
|
|
|
// Process template with campaign data
|
|
const emailBody = processTemplate(template.body, {
|
|
'user.name': user.name,
|
|
'campaign.name': campaign.name,
|
|
'rep.name': representative.name,
|
|
});
|
|
```
|
|
|
|
### System Emails
|
|
|
|
System emails (verification, password reset):
|
|
|
|
```typescript
|
|
// Load system template
|
|
const template = await getTemplateByType('email-verification');
|
|
|
|
// Process with user data
|
|
const emailBody = processTemplate(template.body, {
|
|
'user.name': user.name,
|
|
'verify.link': verificationUrl,
|
|
});
|
|
|
|
// Send email
|
|
await emailService.sendEmail({
|
|
to: user.email,
|
|
subject: template.subject,
|
|
html: emailBody,
|
|
});
|
|
```
|
|
|
|
## Related Documentation
|
|
|
|
- [Template System](template-system.md)
|
|
- [Editor](editor.md)
|
|
- [Variables](variables.md)
|
|
- [Versioning](versioning.md)
|
|
- [Email Templates Page](../../frontend/pages/admin/email-templates-page.md)
|
|
- [Email Template Editor Page](../../frontend/pages/admin/email-template-editor-page.md)
|
|
- [Email Service](../../backend/services/index.md)
|
|
- [Campaign Manager Guide](../../user-guides/campaign-manager-guide.md)
|