@bernierllc/email-template-service
v1.2.0
Published
Email template management service with provider synchronization and variable context validation
Readme
@bernierllc/email-template-service
Email template management service with provider synchronization, variable context validation, and base template support.
Features
- Complete template CRUD operations with validation
- Provider plugin system for email service integration (SendGrid, Mailgun, etc.)
- Bidirectional synchronization between local database and provider services
- Variable context registration and validation
- Base template support for consistent branding
- Conflict detection and resolution strategies
- Batch synchronization with error tracking
- TypeScript-first with strict type safety
- Extensible database adapter interface
Installation
npm install @bernierllc/email-template-serviceQuick Start
import {
EmailTemplateService,
InMemoryDatabaseAdapter,
MockProviderPlugin
} from '@bernierllc/email-template-service';
// Initialize service
const service = new EmailTemplateService({
database: new InMemoryDatabaseAdapter(),
templateEngine: myTemplateEngine,
variableRegistry: myVariableRegistry,
providers: [new MockProviderPlugin()],
syncConfig: {
enabled: true,
providers: {
sendgrid: {
enabled: true,
strategy: 'auto',
direction: 'bidirectional'
}
},
defaultStrategy: 'auto',
conflictResolution: 'local_wins'
}
});
// Create a template
const template = await service.createTemplate({
name: 'Welcome Email',
subject: 'Welcome to our platform, {{firstName}}!',
htmlContent: '<html><body><h1>Welcome {{firstName}} {{lastName}}!</h1></body></html>',
textContent: 'Welcome {{firstName}} {{lastName}}!',
tags: ['welcome', 'onboarding'],
createdBy: 'admin'
});
// Sync to provider
await service.syncToProvider(template.id, 'sendgrid');
// List templates
const result = await service.listTemplates({
category: 'transactional',
page: 1,
limit: 10
});Core Concepts
Templates
Templates are email definitions with support for:
- HTML and text content
- Variable placeholders (e.g.,
{{firstName}}) - Subject lines with variables
- Categorization and tagging
- Versioning
- Provider synchronization status
Provider Plugins
Provider plugins enable integration with email service providers:
- SendGrid: Template management and synchronization
- Mailgun: Template operations and tracking
- Custom: Implement
TemplateProviderPlugininterface
Plugins support:
- Template CRUD operations in provider systems
- Bidirectional synchronization
- Feature capability detection
- Health monitoring and status reporting
Variable Contexts
Variable contexts define available variables for templates:
- Type-safe variable definitions
- Required vs. optional variables
- Context inheritance
- Template validation against contexts
- Auto-completion suggestions
Base Templates
Base templates provide consistent branding:
- Reusable header/footer HTML and CSS
- Theme management
- Branding elements (logos, colors, fonts)
- Dynamic content insertion
- Template building from base + content
API Reference
EmailTemplateService
Template Operations
createTemplate(definition: TemplateDefinition): Promise
Create a new email template.
const template = await service.createTemplate({
name: 'Password Reset',
subject: 'Reset your password',
htmlContent: '<html><body>Click here to reset: {{resetLink}}</body></html>',
context: 'auth',
createdBy: 'admin'
});updateTemplate(id: string, updates: TemplateUpdate): Promise
Update an existing template.
const updated = await service.updateTemplate(template.id, {
subject: 'Reset your password - Updated',
lastModifiedBy: 'admin'
});deleteTemplate(id: string): Promise
Delete a template and its provider copies.
await service.deleteTemplate(template.id);getTemplate(id: string): Promise<Template | null>
Retrieve a template by ID.
const template = await service.getTemplate('tpl_123');listTemplates(options: ListOptions): Promise<PaginatedResult>
List templates with filtering and pagination.
const result = await service.listTemplates({
category: 'marketing',
tags: ['promo'],
isActive: true,
search: 'holiday',
page: 1,
limit: 20,
sortBy: 'createdAt',
sortOrder: 'desc'
});Provider Synchronization
syncToProvider(templateId: string, providerId: string): Promise
Sync a template to a specific provider.
const result = await service.syncToProvider('tpl_123', 'sendgrid');
console.log(result.action); // 'created' or 'updated'
console.log(result.providerTemplateId);syncFromProvider(providerTemplateId: string, providerId: string): Promise
Import a template from a provider.
const template = await service.syncFromProvider('sg_template_456', 'sendgrid');syncAllTemplates(providerId: string): Promise
Sync all local templates to a provider.
const result = await service.syncAllTemplates('sendgrid');
console.log(`Synced: ${result.successful}/${result.total}`);
console.log(`Failed: ${result.failed}`);Base Template Operations
createBaseTemplate(definition: BaseTemplateDefinition): Promise
Create a reusable base template.
const baseTemplate = await service.createBaseTemplate({
name: 'Corporate Email Template',
headerHtml: '<header><img src="{{logo}}" /></header>',
footerHtml: '<footer>© 2025 Company Name</footer>',
theme: 'corporate'
});buildTemplate(baseTemplateId: string, content: string, variables?: Record<string, unknown>): Promise
Build a complete template from base + content.
const built = await service.buildTemplate(
baseTemplate.id,
'<main><h1>{{title}}</h1><p>{{content}}</p></main>',
{
logo: 'https://example.com/logo.png',
title: 'Important Update',
content: 'This is the email body'
}
);
console.log(built.html); // Complete HTML with header, content, footer
console.log(built.text); // Plain text versionVariable Context Management
registerContext(name: string, context: VariableContext): Promise
Register a variable context for templates.
await service.registerContext('user', {
description: 'User-related variables',
variables: {
firstName: { type: 'string', required: true, description: 'User first name' },
lastName: { type: 'string', required: true, description: 'User last name' },
email: { type: 'string', required: true, description: 'User email address' },
accountAge: { type: 'number', required: false, description: 'Days since signup' }
}
});validateTemplate(templateId: string, contextOverride?: string): Promise
Validate a template against its variable context.
const validation = await service.validateTemplate('tpl_123');
if (!validation.isValid) {
console.log('Errors:', validation.errors);
console.log('Undefined variables:', validation.undefinedVariables);
}getVariableSuggestions(context: string, prefix?: string): Promise<VariableSuggestion[]>
Get variable suggestions for auto-completion.
const suggestions = await service.getVariableSuggestions('user', 'first');
// Returns: [{ name: 'firstName', type: 'string', ... }]Database Adapters
The service supports any database through the DatabaseAdapter interface.
In-Memory Adapter (Testing/Development)
import { InMemoryDatabaseAdapter } from '@bernierllc/email-template-service';
const adapter = new InMemoryDatabaseAdapter();Custom Adapter
Implement the DatabaseAdapter interface for your database:
import { DatabaseAdapter, Template, BaseTemplate } from '@bernierllc/email-template-service';
class PostgresDatabaseAdapter implements DatabaseAdapter {
async createTemplate(template: Template): Promise<Template> {
// Insert into PostgreSQL
}
async updateTemplate(id: string, updates: Partial<Template>): Promise<Template> {
// Update PostgreSQL row
}
// Implement other required methods...
}Provider Plugins
Creating a Provider Plugin
import {
BaseProviderPlugin,
Template,
ProviderTemplate,
SyncResult
} from '@bernierllc/email-template-service';
class SendGridTemplatePlugin extends BaseProviderPlugin {
readonly name = 'SendGrid Template Plugin';
readonly version = '1.0.0';
readonly providerId = 'sendgrid';
readonly capabilities = [
{
feature: 'template-versioning',
description: 'Supports template versions',
methods: ['createTemplate', 'updateTemplate']
}
];
async initialize(config: PluginConfig): Promise<void> {
await super.initialize(config);
this.client = new SendGridClient(config.apiKey);
}
async createTemplate(template: Template): Promise<string> {
this.ensureInitialized();
const result = await this.client.createTemplate({
name: template.name,
generation: 'dynamic',
subject: template.subject,
html_content: template.htmlContent
});
return result.id;
}
// Implement other required methods...
}Configuration
Sync Configuration
{
enabled: true, // Enable synchronization
providers: {
sendgrid: {
enabled: true,
strategy: 'auto', // 'auto', 'manual', or 'scheduled'
direction: 'bidirectional', // 'bidirectional', 'push_only', 'pull_only'
schedule: '0 */6 * * *', // Cron expression for scheduled sync
batchSize: 50 // Batch size for bulk operations
}
},
defaultStrategy: 'manual', // Default sync strategy
conflictResolution: 'local_wins' // 'local_wins', 'remote_wins', 'timestamp', 'manual'
}Error Handling
The service provides specific error types:
import {
TemplateNotFoundError,
TemplateValidationError,
ProviderNotFoundError,
SyncError,
SyncConflictError
} from '@bernierllc/email-template-service';
try {
await service.updateTemplate('invalid-id', { name: 'New Name' });
} catch (error) {
if (error instanceof TemplateNotFoundError) {
console.error('Template not found');
} else if (error instanceof TemplateValidationError) {
console.error('Validation errors:', error.errors);
} else if (error instanceof SyncError) {
console.error('Sync failed:', error.message);
}
}Testing
The package includes comprehensive tests using real data:
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Run tests once (CI)
npm run test:runDependencies
Required
@bernierllc/template-variable-registry- Variable context management@bernierllc/email-template-engine- Template processing@bernierllc/email-sender- Email sending abstraction@bernierllc/logger- Service logging
Optional
@bernierllc/cache-manager- Template caching@bernierllc/retry-policy- Provider operation retries
Integration Status
- Logger: Integrated - All service operations and provider sync events logged
- Docs-Suite: Ready - Complete API documentation with examples
- NeverHub: Required - Template events, sync status, and provider health monitoring
License
Copyright (c) 2025 Bernier LLC. All rights reserved.
See Also
- @bernierllc/email-template-engine - Template processing and rendering
- @bernierllc/template-variable-registry - Variable context management
- @bernierllc/email-sender - Email sending service
- @bernierllc/email-sendgrid-plugin - SendGrid provider plugin
