@bernierllc/email-service

中文文档
6.0.10发布于 2026/11/05PROPRIETARYTypeScriptES Module近 30 天下载 1976

Comprehensive email service orchestrating template management, multi-provider delivery, tracking, and subscriber management

原始使用文档
文档目录27 节
  1. Features
  2. Installation
  3. Peer Dependencies
  4. Usage
  5. Quick Start
  6. Core Concepts
  7. 1. Multi-Provider Email Sending
  8. 2. Template Management
  9. 3. Magic Link Authentication
  10. 4. Retry Logic & Email Validation
  11. 5. Delivery Tracking
  12. 4. Subscriber Management
  13. 5. Scheduled Emails
  14. 6. Bulk Sending
  15. 7. Webhook Handling
  16. API Reference
  17. EmailService
  18. Type Definitions
  19. Best Practices
  20. Error Handling
  21. Template Variables
  22. Rate Limiting
  23. Monitoring
  24. Dependencies
  25. Integration Status
  26. Examples
  27. License

@bernierllc/email-service

Comprehensive email service orchestrating template management, multi-provider delivery, tracking, and subscriber management.

Features

  • Multi-Provider Support - SendGrid, Mailgun, AWS SES, and SMTP
  • Template Management - Create, update, and render email templates with variable substitution
  • Magic Link Authentication - Secure, time-limited authentication links for passwordless login
  • Automatic Retry Logic - Exponential backoff with jitter for transient failures
  • Email Validation - Validate recipient addresses before sending (syntax, domain, MX records)
  • Delivery Tracking - Track email delivery, opens, clicks, and bounces
  • Subscriber Management - Manage subscribers, lists, and preferences
  • Queue Integration - Schedule and send emails in background
  • Webhook Handling - Process provider webhooks for delivery events
  • Database Persistence - Store templates, delivery records, and subscribers
  • Analytics - Comprehensive delivery statistics and reporting

Installation

npm install @bernierllc/email-service

Peer Dependencies

Install email provider(s) you need:

# SendGrid
npm install @sendgrid/mail

# SMTP (included)
npm install nodemailer

Usage

Quick Start

import { EmailService } from '@bernierllc/email-service';

const service = new EmailService({
  providers: [
    {
      type: 'smtp',
      smtp: {
        host: 'smtp.gmail.com',
        port: 587,
        secure: false,
        auth: { user: '[email protected]', pass: 'password' }
      }
    }
  ],
  defaultProvider: 'smtp',
  database: {
    type: 'sqlite',
    database: './data/email.db'
  },
  templates: {
    cacheEnabled: true,
    cacheTTL: 3600
  },
  tracking: {
    enabled: true,
    domain: 'yourdomain.com'
  }
});

await service.initialize();

// Send an email
const result = await service.send({
  from: '[email protected]',
  to: ['[email protected]'],
  subject: 'Welcome!',
  html: '<h1>Hello!</h1><p>Welcome to our service.</p>'
});

console.log(`Email sent: ${result.messageId}`);

Core Concepts

1. Multi-Provider Email Sending

// Configure multiple providers
const service = new EmailService({
  providers: [
    {
      type: 'sendgrid',
      apiKey: process.env.SENDGRID_API_KEY
    },
    {
      type: 'mailgun',
      apiKey: process.env.MAILGUN_API_KEY,
      domain: 'mg.yourdomain.com'
    },
    {
      type: 'ses',
      region: 'us-east-1',
      apiKey: process.env.AWS_ACCESS_KEY,
      secretKey: process.env.AWS_SECRET_KEY
    },
    {
      type: 'smtp',
      smtp: {
        host: 'smtp.gmail.com',
        port: 587,
        secure: false,
        auth: {
          user: process.env.SMTP_USER,
          pass: process.env.SMTP_PASS
        }
      }
    }
  ],
  defaultProvider: 'sendgrid',
  database: { type: 'sqlite', database: './email.db' }
});

// Send via specific provider
await service.send({
  from: '[email protected]',
  to: ['[email protected]'],
  subject: 'Test',
  html: '<p>Test</p>',
  provider: 'mailgun' // Override default
});

2. Template Management

// Create template
const template = await service.createTemplate({
  name: 'welcome-email',
  subject: 'Welcome {{name}}!',
  html: `
    <h1>Hello {{name}}</h1>
    <p>Welcome to {{company}}!</p>
    <p>Your account email is: {{email}}</p>
  `,
  text: 'Hello {{name}}, welcome to {{company}}!'
});

// Send using template
await service.send({
  from: '[email protected]',
  to: ['[email protected]'],
  templateId: template.id,
  templateData: {
    name: 'John Doe',
    company: 'Acme Corp',
    email: '[email protected]'
  }
});

// Update template
await service.updateTemplate(template.id, {
  subject: 'Welcome to {{company}}, {{name}}!',
  html: '<h1>Welcome {{name}}!</h1>'
});

// Get template
const retrieved = await service.getTemplate(template.id);
console.log(retrieved.variables); // ['name', 'company', 'email']

// Delete template
await service.deleteTemplate(template.id);

Send secure, time-limited authentication links for passwordless login, email verification, password resets, and more.

// Configure magic link support
const service = new EmailService({
  providers: [/* ... */],
  database: {/* ... */},
  magicLink: {
    secret: process.env.MAGIC_LINK_SECRET, // Required: Secret key for signing tokens
    expirationMinutes: 30,                  // Optional: Default 60 minutes
    issuer: 'YourApp'                       // Optional: Token issuer name
  }
});

await service.initialize();

// Send magic link for passwordless login
const result = await service.sendMagicLink({
  recipient: '[email protected]',
  purpose: 'sign in',
  redirectUrl: 'https://app.example.com/auth/verify',
  subject: 'Your Login Link',              // Optional: Custom subject
  expirationMinutes: 15                    // Optional: Override default expiration
});

console.log(result.magicLink);  // https://app.example.com/auth/verify?token=eyJ...
console.log(result.token);      // eyJ... (signed JWT token)
console.log(result.expiresAt);  // 2025-01-15T12:45:00.000Z

// Send with custom data in token
const resetResult = await service.sendMagicLink({
  recipient: '[email protected]',
  purpose: 'reset your password',
  redirectUrl: 'https://app.example.com/reset-password',
  customData: {
    userId: '12345',
    action: 'password-reset'
  }
});

// Use custom template for magic link email
const welcomeResult = await service.sendMagicLink({
  recipient: '[email protected]',
  purpose: 'verify your email',
  redirectUrl: 'https://app.example.com/verify',
  template: 'welcome-verification',  // Use existing template
  templateData: {
    userName: 'John Doe',
    companyName: 'Acme Corp'
  }
});

Magic Link Features:

  • ✅ Secure signed tokens using @bernierllc/crypto-utils
  • ✅ Configurable expiration times
  • ✅ Custom data embedded in token
  • ✅ Default professional email template (or use your own)
  • ✅ Automatic URL parameter handling (existing query params preserved)
  • ✅ Support for all email providers

Verifying Magic Link Tokens:

import { verifySignedToken } from '@bernierllc/crypto-utils';

// In your auth/verify endpoint
app.get('/auth/verify', async (req, res) => {
  const token = req.query.token as string;

  try {
    const payload = await verifySignedToken(
      token,
      process.env.MAGIC_LINK_SECRET!
    );

    // Token is valid - log user in
    console.log(payload.email);      // [email protected]
    console.log(payload.purpose);    // 'sign in'
    console.log(payload.customData); // Any custom data you included

    // Create session and redirect
    req.session.userId = payload.email;
    res.redirect('/dashboard');
  } catch (error) {
    // Token expired, invalid, or tampered with
    res.status(401).send('Invalid or expired link');
  }
});

4. Retry Logic & Email Validation

Automatic retry with exponential backoff and email address validation.

const service = new EmailService({
  providers: [/* ... */],
  database: {/* ... */},

  // Retry configuration (optional)
  retry: {
    maxRetries: 3,                  // Number of retry attempts
    initialDelayMs: 1000,           // Initial delay between retries
    maxDelayMs: 30000,              // Maximum delay
    jitter: true,                   // Add randomness to delays
    enableMetrics: true             // Track retry metrics
  },

  // Email validation (optional)
  validation: {
    validateRecipients: true,       // Validate email addresses before sending
    strict: true                    // Use strict validation rules
  }
});

// Emails will automatically retry on transient failures
const result = await service.send({
  to: '[email protected]',
  subject: 'Test',
  html: '<p>This will retry up to 3 times if it fails</p>'
});

console.log(result.retryCount); // Number of retries that occurred

Retry Features:

  • ✅ Exponential backoff with jitter to avoid thundering herd
  • ✅ Configurable max retries and delays
  • ✅ Automatic retry on transient failures
  • ✅ Retry metrics tracking (attempts, successes, failures)
  • ✅ Integrates with @bernierllc/retry-policy, retry-state, and retry-metrics

Validation Features:

  • ✅ Syntax validation (RFC 5322 compliance)
  • ✅ Domain validation (MX record checks when strict mode enabled)
  • ✅ Disposable email detection
  • ✅ Multiple recipient validation
  • ✅ Integrates with @bernierllc/email-validator

5. Delivery Tracking

// Send email
const result = await service.send({
  from: '[email protected]',
  to: ['[email protected]'],
  subject: 'Order Confirmation',
  html: '<h1>Thanks for your order!</h1>'
});

// Get delivery record
const delivery = await service.getDelivery(result.deliveryId);
console.log(delivery.status); // 'sent', 'delivered', 'opened', 'clicked', etc.

// Track opens
await service.trackOpen(result.deliveryId);

// Track clicks
await service.trackClick(result.deliveryId);

// Get statistics
const stats = await service.getDeliveryStats();
console.log(`Open rate: ${stats.openRate}%`);
console.log(`Click rate: ${stats.clickRate}%`);
console.log(`Bounce rate: ${stats.bounceRate}%`);

// Get statistics for date range
const monthStats = await service.getDeliveryStats(
  new Date('2025-01-01'),
  new Date('2025-01-31')
);

4. Subscriber Management

// Create subscriber
const subscriber = await service.createSubscriber({
  email: '[email protected]',
  name: 'John Doe',
  lists: ['newsletter', 'updates'],
  tags: ['premium', 'early-adopter'],
  metadata: {
    source: 'website',
    signupDate: new Date()
  }
});

// Get subscriber
const found = await service.getSubscriber(subscriber.id);

// Update subscriber
await service.updateSubscriber(subscriber.id, {
  name: 'John Smith',
  tags: ['premium', 'verified']
});

// Unsubscribe
await service.unsubscribe('[email protected]');

// Create subscriber list
const list = await service.createList(
  'Monthly Newsletter',
  'Our monthly product updates and news'
);

5. Scheduled Emails

// Configure queue
const service = new EmailService({
  providers: [/* ... */],
  database: { type: 'sqlite', database: './email.db' },
  queue: {
    backend: new MemoryBackend(),
    concurrency: 5,
    retryPolicy: {
      maxAttempts: 3,
      backoff: { type: 'exponential', delay: 1000 }
    }
  }
});

// Schedule for later
await service.send({
  from: '[email protected]',
  to: ['[email protected]'],
  subject: 'Reminder',
  html: '<p>This is your reminder</p>',
  scheduledAt: new Date(Date.now() + 24 * 60 * 60 * 1000) // 24 hours
});

// Send with priority
await service.send({
  from: '[email protected]',
  to: ['[email protected]'],
  subject: 'URGENT: System Alert',
  html: '<p>Critical alert</p>',
  priority: 'high' // high, normal, low
});

6. Bulk Sending

const results = await service.sendBulk([
  {
    from: '[email protected]',
    to: ['[email protected]'],
    subject: 'Personalized for User 1',
    html: '<p>Hello User 1</p>'
  },
  {
    from: '[email protected]',
    to: ['[email protected]'],
    subject: 'Personalized for User 2',
    html: '<p>Hello User 2</p>'
  }
]);

results.forEach((result, index) => {
  console.log(`Email ${index + 1}: ${result.success ? 'sent' : 'failed'}`);
});

7. Webhook Handling

// Register webhook handler
service.registerWebhookHandler('delivered', async (event) => {
  console.log(`Email ${event.messageId} was delivered`);
  // Update your database, trigger workflows, etc.
});

service.registerWebhookHandler('opened', async (event) => {
  console.log(`Email ${event.messageId} was opened`);
  // Track user engagement
});

service.registerWebhookHandler('clicked', async (event) => {
  console.log(`Link clicked in ${event.messageId}`);
  // Track click-through rates
});

service.registerWebhookHandler('bounced', async (event) => {
  console.log(`Email ${event.messageId} bounced`);
  // Update subscriber status
  await service.unsubscribe(event.data.email);
});

// Process webhook from provider
await service.handleWebhook({
  provider: 'sendgrid',
  event: 'delivered',
  messageId: 'msg_123',
  timestamp: new Date(),
  data: { /* provider-specific data */ }
});

API Reference

EmailService

Constructor

new EmailService(config: EmailServiceConfig)

Configuration:

interface EmailServiceConfig {
  providers: ProviderConfig[];
  defaultProvider?: EmailProvider;
  database: DatabaseConfig;
  queue?: QueueOptions;
  templates?: {
    cacheEnabled?: boolean;
    cacheTTL?: number;
  };
  tracking?: {
    enabled?: boolean;
    domain?: string;
  };
  compliance?: {
    unsubscribeLink?: boolean;
    footerRequired?: boolean;
  };
}

interface ProviderConfig {
  type: 'sendgrid' | 'mailgun' | 'ses' | 'smtp';
  apiKey?: string;
  domain?: string;
  region?: string;
  smtp?: SMTPConfig;
  rateLimit?: RateLimitConfig;
}

Methods

Email Sending
  • send(request: EmailRequest): Promise<SendEmailResult> - Send email
  • sendBulk(requests: EmailRequest[]): Promise<SendEmailResult[]> - Send multiple emails
Template Management
  • createTemplate(request: TemplateCreateRequest): Promise<EmailTemplate> - Create template
  • getTemplate(id: string): Promise<EmailTemplate | null> - Get template
  • updateTemplate(id: string, update: TemplateUpdateRequest): Promise<EmailTemplate> - Update template
  • deleteTemplate(id: string): Promise<boolean> - Delete template
Delivery Tracking
  • getDelivery(id: string): Promise<DeliveryRecord | null> - Get delivery record
  • trackOpen(deliveryId: string): Promise<void> - Track email open
  • trackClick(deliveryId: string): Promise<void> - Track link click
  • getDeliveryStats(startDate?: Date, endDate?: Date): Promise<DeliveryStats> - Get statistics
Subscriber Management
  • createSubscriber(request: SubscriberCreateRequest): Promise<Subscriber> - Create subscriber
  • getSubscriber(id: string): Promise<Subscriber | null> - Get subscriber
  • updateSubscriber(id: string, update: SubscriberUpdateRequest): Promise<Subscriber> - Update subscriber
  • unsubscribe(email: string): Promise<boolean> - Unsubscribe email
  • createList(name: string, description?: string): Promise<SubscriberList> - Create list
Webhook Handling
  • registerWebhookHandler(event: string, handler: WebhookHandler): void - Register handler
  • handleWebhook(event: WebhookEvent): Promise<void> - Process webhook
Lifecycle
  • initialize(): Promise<void> - Initialize service
  • shutdown(): Promise<void> - Cleanup and shutdown

Type Definitions

interface EmailRequest {
  from: EmailAddress | string;
  to: EmailAddress[] | string[];
  cc?: EmailAddress[] | string[];
  bcc?: EmailAddress[] | string[];
  subject: string;
  html?: string;
  text?: string;
  templateId?: string;
  templateData?: TemplateContext;
  attachments?: EmailAttachment[];
  headers?: Record<string, string>;
  tags?: string[];
  metadata?: Record<string, any>;
  priority?: 'high' | 'normal' | 'low';
  scheduledAt?: Date;
  provider?: EmailProvider;
}

interface SendEmailResult {
  success: boolean;
  messageId?: string;
  deliveryId?: string;
  provider?: EmailProvider;
  error?: string;
  timestamp: Date;
  queuedForLater?: boolean;
}

interface DeliveryStats {
  total: number;
  sent: number;
  delivered: number;
  opened: number;
  clicked: number;
  bounced: number;
  failed: number;
  openRate: number;
  clickRate: number;
  bounceRate: number;
}

enum DeliveryStatus {
  QUEUED = 'queued',
  SENDING = 'sending',
  SENT = 'sent',
  DELIVERED = 'delivered',
  OPENED = 'opened',
  CLICKED = 'clicked',
  BOUNCED = 'bounced',
  FAILED = 'failed',
  UNSUBSCRIBED = 'unsubscribed'
}

Best Practices

Error Handling

try {
  await service.send(emailRequest);
} catch (error) {
  if (error instanceof ProviderError) {
    // Switch to backup provider
    console.error('Provider failed:', error.provider);
  } else if (error instanceof TemplateError) {
    // Template rendering failed
    console.error('Template error:', error.message);
  } else if (error instanceof DeliveryError) {
    // Delivery failed
    console.error('Delivery error:', error.message);
  }
}

Template Variables

// Always validate template data matches template variables
const template = await service.getTemplate(templateId);
const missingVars = template.variables.filter(
  v => !(v in templateData)
);
if (missingVars.length > 0) {
  throw new Error(`Missing template variables: ${missingVars.join(', ')}`);
}

Rate Limiting

// Configure per-provider rate limits
const service = new EmailService({
  providers: [
    {
      type: 'sendgrid',
      apiKey: process.env.SENDGRID_API_KEY,
      rateLimit: {
        maxPerSecond: 100,
        maxPerMinute: 5000,
        maxPerHour: 100000
      }
    }
  ],
  // ...
});

Monitoring

// Regular health monitoring
setInterval(async () => {
  const stats = await service.getDeliveryStats();

  if (stats.bounceRate > 5) {
    console.warn('High bounce rate detected:', stats.bounceRate);
  }

  if (stats.failed > 100) {
    console.error('High failure count:', stats.failed);
  }
}, 60000); // Every minute

Dependencies

This package orchestrates:

Integration Status

  • Logger: Integrated - Uses @bernierllc/logger for structured logging
  • Docs-Suite: Ready - Markdown documentation available
  • NeverHub integration: Planned - Service discovery and event bus integration with @bernierllc/neverhub-adapter

Examples

See the examples directory for complete working examples:

  • basic-smtp.ts - Basic SMTP email sending
  • templates.ts - Template management and rendering
  • tracking.ts - Delivery tracking and analytics
  • subscribers.ts - Subscriber management
  • webhooks.ts - Webhook handling
  • multi-provider.ts - Multi-provider configuration

License

Copyright (c) 2025 Bernier LLC. All rights reserved.

This package is proprietary software licensed for use only within the scope of the project it was delivered for.

版本与发布记录

@bernierllc/email-service 共发布 30 个版本,首次发布于 2025/10/08;过去 12 个月发布了 28 个版本。

版本发布日期距今
6.0.10latest2026/11/053 天前
6.0.92026/11/053 天前
6.0.82026/10/2415 天前
6.0.72026/10/2316 天前
6.0.62026/10/1920 天前
6.0.52026/10/021 个月前

关于 @bernierllc/email-service 的常见问题

@bernierllc/email-service 是什么?

Comprehensive email service orchestrating template management, multi-provider delivery, tracking, and subscriber management

如何安装 @bernierllc/email-service?

在项目目录运行 npm install @bernierllc/email-service,或使用 pnpm add / yarn add / bun add。

@bernierllc/email-service 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@bernierllc/email-service 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@bernierllc/email-service 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@bernierllc/email-service 可以商用吗?

@bernierllc/email-service 使用 PROPRIETARY 许可。声明的许可为 PROPRIETARY,请阅读许可原文确认使用条件。以上为概括,不构成法律意见,请以许可原文为准。

@bernierllc/email-service 的下载量有多少?

根据 npm 官方下载统计,@bernierllc/email-service 在 2026/10/08 – 2026/11/06 这 30 天内被下载 1,976 次,日均约 66 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@bernierllc/email-service 还在维护吗?

最新版本 6.0.10 发布于 2026/11/05(3 天前);至今共发布 30 个版本,其中过去 12 个月发布了 28 个;首次发布于 2025/10/08。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。