Phase 2 Implementation: - Add RSS feed discovery links to footer (Subscribe section) - Create email templates (base-template.html, research-updates-content.html) - Add comprehensive newsletter sending implementation plan - Fix CSP check to exclude email-templates directory Email templates use inline styles for cross-client compatibility (Gmail, Outlook, Apple Mail) and are excluded from CSP checks. Next steps: Install dependencies (handlebars, @sendgrid/mail), implement EmailService, controller methods, and admin UI. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
134 lines
4.4 KiB
Markdown
134 lines
4.4 KiB
Markdown
# Email Templates for Newsletter Tiers
|
|
|
|
This directory contains HTML email templates for the four newsletter subscription tiers:
|
|
|
|
1. **research-updates.html** - Monthly research insights (scholarly audience)
|
|
2. **implementation-notes.html** - Bi-weekly implementation guidance (practitioners)
|
|
3. **governance-discussions.html** - Sporadic values/governance topics (stakeholders)
|
|
4. **project-updates.html** - Quarterly project milestones (general audience)
|
|
|
|
## Template Variables
|
|
|
|
All templates use Mustache-style {{variables}} for dynamic content:
|
|
|
|
- `{{name}}` - Subscriber name
|
|
- `{{unsubscribe_link}}` - Unsubscribe URL
|
|
- `{{preferences_link}}` - Preferences management URL
|
|
- `{{website_link}}` - https://agenticgovernance.digital
|
|
- `{{docs_link}}` - https://agenticgovernance.digital/docs.html
|
|
- `{{github_link}}` - https://github.com/AgenticGovernance/tractatus-framework
|
|
- Content-specific variables documented in each template
|
|
|
|
## Usage
|
|
|
|
Templates are loaded by the newsletter admin UI and processed with a template engine (e.g., Handlebars, Mustache) before sending via email service.
|
|
|
|
## Design Principles
|
|
|
|
- Inline CSS for email client compatibility
|
|
- Responsive design (mobile-friendly)
|
|
- Accessible (semantic HTML, sufficient contrast)
|
|
- Brand-consistent (blue gradient header, clean typography)
|
|
- Clear CTA buttons with good hit targets
|
|
- Unsubscribe link always visible in footer
|
|
|
|
## Template Usage
|
|
|
|
### Base Template (`base-template.html`)
|
|
|
|
The base template provides the outer HTML structure with header, footer, and styling. It uses these placeholders:
|
|
|
|
- `{{email_title}}` - Email subject (for <title> tag)
|
|
- `{{header_title}}` - Main header text (e.g., "Tractatus Research Updates")
|
|
- `{{header_subtitle}}` - Subtitle text (e.g., "Monthly insights from AI governance research")
|
|
- `{{name}}` - Subscriber name
|
|
- `{{content_body}}` - HTML content injected here
|
|
- `{{tier_name}}` - Newsletter tier name (for footer)
|
|
- `{{unsubscribe_link}}` - Unsubscribe URL
|
|
- `{{preferences_link}}` - Preferences management URL
|
|
|
|
### Content Modules
|
|
|
|
Content modules are HTML snippets that get injected into `{{content_body}}`. Example:
|
|
- `research-updates-content.html` - Research Updates tier content structure
|
|
|
|
### Implementation with Template Engine
|
|
|
|
```javascript
|
|
const Handlebars = require('handlebars');
|
|
const fs = require('fs');
|
|
|
|
// Load templates
|
|
const baseTemplate = fs.readFileSync('email-templates/base-template.html', 'utf8');
|
|
const contentModule = fs.readFileSync('email-templates/research-updates-content.html', 'utf8');
|
|
|
|
// Compile
|
|
const compiledContent = Handlebars.compile(contentModule);
|
|
const compiledBase = Handlebars.compile(baseTemplate);
|
|
|
|
// Render content
|
|
const renderedContent = compiledContent({
|
|
highlight_1_title: "...",
|
|
highlight_1_summary: "...",
|
|
// ... all other variables
|
|
});
|
|
|
|
// Render final email
|
|
const finalEmail = compiledBase({
|
|
email_title: "Tractatus Research Updates - November 2025",
|
|
header_title: "Tractatus Research Updates",
|
|
header_subtitle: "Monthly insights from AI governance research",
|
|
name: subscriber.name || "there",
|
|
content_body: renderedContent,
|
|
tier_name: "Research Updates",
|
|
unsubscribe_link: `https://agenticgovernance.digital/api/newsletter/unsubscribe?token=${subscriber.token}`,
|
|
preferences_link: `https://agenticgovernance.digital/newsletter/preferences?token=${subscriber.token}`
|
|
});
|
|
```
|
|
|
|
### Plain Text Version
|
|
|
|
Always generate a plain-text version alongside HTML for accessibility and spam filtering:
|
|
|
|
```javascript
|
|
const htmlToText = require('html-to-text');
|
|
const plainText = htmlToText.convert(finalEmail, {
|
|
wordwrap: 80,
|
|
ignoreImages: true
|
|
});
|
|
```
|
|
|
|
### Testing
|
|
|
|
Test emails with [Litmus](https://www.litmus.com/) or [Email on Acid](https://www.emailonacid.com/) across:
|
|
- Gmail (desktop, mobile)
|
|
- Outlook (2016+, 365)
|
|
- Apple Mail (macOS, iOS)
|
|
- Yahoo Mail
|
|
- Thunderbird
|
|
|
|
### Sending
|
|
|
|
Use a transactional email service:
|
|
- **SendGrid**: https://sendgrid.com/
|
|
- **Mailgun**: https://www.mailgun.com/
|
|
- **AWS SES**: https://aws.amazon.com/ses/
|
|
|
|
Example with SendGrid:
|
|
|
|
```javascript
|
|
const sgMail = require('@sendgrid/mail');
|
|
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
|
|
|
|
await sgMail.send({
|
|
to: subscriber.email,
|
|
from: 'research@agenticgovernance.digital',
|
|
subject: 'Tractatus Research Updates - November 2025',
|
|
html: finalEmail,
|
|
text: plainText,
|
|
trackingSettings: {
|
|
clickTracking: { enable: true },
|
|
openTracking: { enable: true }
|
|
}
|
|
});
|
|
```
|