@bernierllc/email-service

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

综合电子邮件服务组织模板管理、多供应商交付、跟踪和用户管理

中文使用文档
文档目录27 节
  1. 特征
  2. 安装
  3. 同伴依赖关系
  4. 使用量
  5. 快速启动
  6. 核心概念
  7. 1. 多服务电子邮件发送
  8. 2. 模板管理
  9. 3. 魔法链接认证
  10. 4. 重试逻辑和电子邮件验证
  11. 5. 交付跟踪
  12. 4. 订户管理
  13. 5. 排定的电子邮件
  14. 6. 散装发送
  15. 7. 网络垃圾处理
  16. API 参考
  17. 电子邮件服务
  18. 类型定义
  19. 最佳做法
  20. 处理错误
  21. 模板变量
  22. 限制费率
  23. 监测
  24. 依赖关系
  25. 一体化状况
  26. 实例
  27. 许可证

@bernierllc/电子邮件服务

综合电子邮件服务组织模板管理、多供应商交付、跟踪和用户管理.

特征

  • 多服务支持 - 发送Grid、Mailgun、AWSSES和SMTP
  • 模板管理 - 创建、更新和提供可变替代的电子邮件模板
  • 魔法链接认证 - 无密码登录的安全、有时间限制的认证链接
  • 自动重试逻辑 - 暂时性故障时与焦急的对照
  • 电子邮件验证 - 发送前验证收件人地址(语法、域名、MX记录)
  • 交货跟踪 - 跟踪电子邮件发送,打开、点击和回放
  • 订户管理 - 管理订阅者、名单和偏好
  • 队列集成 - 背景安排和发送电子邮件
  • Webhook 处理 - 流程提供商为交付活动提供网点
  • 数据库持久性 - 储存模板、交付记录和订户
  • 分析 - 全面交付统计和报告

安装

npm install @bernierllc/email-service

同伴依赖关系

安装您需要的电子邮件提供者 :

# SendGrid
npm install @sendgrid/mail

# SMTP (included)
npm install nodemailer

使用量

快速启动

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}`);

核心概念

1. 多服务电子邮件发送

// 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. 模板管理

// 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);

发送安全,有时间限制的认证链接用于无密码登录,电子邮件验证,密码重置等.

// 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'
  }
});

魔法链接特性数字 :

  • 使用安全签名符 @bernierllc/crypto-utils
  • * 配置到期时间
  • QQ 自定义数据嵌入符号
  • QQ 默认专业电子邮件模板( 或使用自己的)
  • QQ 自动 URL 参数处理( 已保存查询参数)
  • QQ 对所有电子邮件提供者的支持

正在校验魔法链接键数字 :

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. 重试逻辑和电子邮件验证

自动重试以指数回放和电子邮件地址验证 .

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

重试特性数字 :

  • * * 与焦躁相呼应,避免雷鸣群
  • QQ 可配置的最大重试和延迟
  • QQ 在瞬态失败时自动重试
  • * 重试指标跟踪(尝试、成功、失败)
  • 与 @bernierllc/retry-policy, (中文(简体) ), retry-state,以及 retry-metrics

验证特征数字 :

  • 语法验证(RFC 5322遵守)
  • QQ域验证( 启用严格模式时的 MX 记录检查)
  • QQ 可处理的电子邮件检测
  • ++ 多个收件人验证
  • 与 @bernierllc/email-validator

5. 交付跟踪

// 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. 订户管理

// 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. 排定的电子邮件

// 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. 散装发送

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. 网络垃圾处理

// 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 参考

电子邮件服务

构造器

new EmailService(config: EmailServiceConfig)

配置 :

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;
}

方法

电子邮件发送
  • send(request: EmailRequest): Promise<SendEmailResult> - 发送电子邮件
  • sendBulk(requests: EmailRequest[]): Promise<SendEmailResult[]> - 发送多封电子邮件
模板管理
  • createTemplate(request: TemplateCreateRequest): Promise<EmailTemplate> - 创建模板
  • getTemplate(id: string): Promise<EmailTemplate | null> - 获取模板
  • updateTemplate(id: string, update: TemplateUpdateRequest): Promise<EmailTemplate> - 更新模板
  • deleteTemplate(id: string): Promise<boolean> - 删除模板
交货跟踪
  • getDelivery(id: string): Promise<DeliveryRecord | null> - 拿到交货记录
  • trackOpen(deliveryId: string): Promise<void> - 跟踪电子邮件打开
  • trackClick(deliveryId: string): Promise<void> - 点击音轨链接
  • getDeliveryStats(startDate?: Date, endDate?: Date): Promise<DeliveryStats> - 获取统计数据
订户管理
  • createSubscriber(request: SubscriberCreateRequest): Promise<Subscriber> - 创建订阅者
  • getSubscriber(id: string): Promise<Subscriber | null> - 获取订阅者
  • updateSubscriber(id: string, update: SubscriberUpdateRequest): Promise<Subscriber> - 更新用户
  • unsubscribe(email: string): Promise<boolean> - 取消订阅电子邮件
  • createList(name: string, description?: string): Promise<SubscriberList> - 创建列表
Webhook 处理
  • registerWebhookHandler(event: string, handler: WebhookHandler): void - 登记员
  • handleWebhook(event: WebhookEvent): Promise<void> - 进程网点
生命周期
  • initialize(): Promise<void> - 服务初始化
  • shutdown(): Promise<void> - 清理和关闭

类型定义

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'
}

最佳做法

处理错误

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);
  }
}

模板变量

// 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(', ')}`);
}

限制费率

// 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
      }
    }
  ],
  // ...
});

监测

// 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

依赖关系

此套件的管弦乐 :

一体化状况

  • 锁定器: 集成 - 用于结构化记录的用法@ bennellc/logger
  • 多克套装: 准备 - 有标记文档
  • NeverHub 整合: 计划 - 服务发现和事件总线集成@bernierllc/neverhub-adapter

实例

见 示例目录 用于完整的工作示例:

  • basic-smtp.ts - 基本SMTP电子邮件发送
  • templates.ts - 模板管理和渲染
  • tracking.ts - 交货跟踪和分析
  • subscribers.ts - 订户管理
  • webhooks.ts - 网页浏览处理
  • multi-provider.ts - 多供应商配置

许可证

版权(c)2025 Bernier有限责任公司。 版权所有.

这个软件包是专有软件,只许可在它交付的项目范围内使用.

版本与发布记录

@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 是什么?

综合电子邮件服务组织模板管理、多供应商交付、跟踪和用户管理

如何安装 @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 和提交记录判断。