# @bernierllc/email-manager 中文文档

规范地址：https://npmcn.com/package/%40bernierllc/email-manager/

版本：0\.12\.3
npm 元数据更新时间：2026-11-05T01:28:15.602Z
中文译文更新时间：2026-11-07T23:51:56.807Z
软件包许可：Bernier LLC

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40bernierllc/email-manager
原文对照：https://npmcn.com/package/%40bernierllc/email-manager/?lang=original
项目主页：https://github.com/bernier-llc/tools#readme
源码仓库：https://github.com/bernier-llc/tools

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：624 kB，95 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：26 个
- peer 依赖：ioredis \>=5\.0\.0
- 首次发布：2025-08-21T19:33:38.294Z
- 最新版本发布：2026-11-05T01:28:15.390Z
- 近 30 天下载量：1974（2026-10-08 至 2026-11-06，npm 官方下载统计）
- 已发布版本数：38（近 12 个月 37 个）

## 中文简介

完整的电子邮件管理套件,包含模板管理,调度,分析,以及提供者的管弦乐(仅节点.js - 浏览器使用@bernierllc/电子邮件-manager-客户端)

## 安装

```sh
npm install @bernierllc/email-manager
```

也可以使用：`pnpm add @bernierllc/email-manager`、`yarn add @bernierllc/email-manager`、`bun add @bernierllc/email-manager`

## README

# @bernierllc/电子邮件管理员

一个全面的电子邮件管理服务,负责管理电子邮件发送、模板管理、时间安排和分析。 此服务与 `@bernierllc/email-sender`, (中文(简体) ), `@bernierllc/template-engine`,以及 `@bernierllc/magic-link` 提供完整的电子邮件解决方案.

## 只有节点.js

**此软件包是 Node.js- only** 并且由于Node.js的依赖关系(nodemailer等)而无法被捆绑用于浏览器.

**用于浏览器/前端应用程序**,使用时 [`@bernierllc/email-manager-client`](https://npmcn.com/package/%40bernierllc/email-manager-client/README.md) 相反,它通过HTTP呼叫提供相同的API.

## 特征

### 🚀 **电子邮件管弦乐团**

-   **多供应商支助** 自动失效
-   **基于模板的电子邮件** 有动态内容渲染
-   **电子邮件时间安排** 重试逻辑
-   **批量电子邮件处理** 用于大宗业务

### 📝 **模板管理**

-   **CRUD 操作** 电子邮件模板
-   **模板版本** 生命周期管理
-   **变量验证** 和语法检查
-   **基于职类的组织**

### 🔧 **供应商管理**

-   **多提供者配置** (SendGrid、Mailgun、AWS SES、SMTP、邮戳)
-   **提供者健康监测** 和状态跟踪
-   **限制费率** 和使用情况跟踪
-   **自动失效** 提供者之间

### 📊 **分析和报告**

-   **电子邮件性能跟踪** (打开,点击,弹出)
-   **交付报告** 弹出分析
-   **供应商业绩衡量标准**
-   **历史数据** 和趋势分析

### ⏰ **日程安排系统**

-   **基于队列的排程** 准确的时间
-   **重试逻辑** 交付失败
-   **附表管理** (取消,修改)
-   **背景处理** 自动清理

## 安装

```bash
npm install @bernierllc/email-manager
```

## 依赖关系

这个软件包需要以下伯尼RLC核心软件包:

```bash
npm install @bernierllc/email-sender @bernierllc/template-engine @bernierllc/magic-link
```

## 快速启动

```typescript
import { EmailManager, EmailManagerConfig } from '@bernierllc/email-manager';

// Configure providers
const config: EmailManagerConfig = {
  providers: [
    {
      id: 'sendgrid',
      name: 'SendGrid',
      type: 'sendgrid',
      config: { apiKey: process.env.SENDGRID_API_KEY },
      isActive: true,
      priority: 1
    }
  ],
  analytics: { enabled: true },
  scheduling: { enabled: true }
};

// Initialize manager
const emailManager = new EmailManager(config);

// Send email
const result = await emailManager.sendEmail({
  to: 'user@example.com',
  subject: 'Hello World',
  html: '<h1>Hello!</h1><p>This is a test email.</p>',
  text: 'Hello! This is a test email.'
});

console.log('Email sent:', result.success);
```

## 核心 API

### 电子邮件操作

#### 发送电子邮件

```typescript
const result = await emailManager.sendEmail({
  to: ['user1@example.com', 'user2@example.com'],
  cc: ['manager@example.com'],
  subject: 'Important Update',
  html: '<h1>Update</h1><p>Important information...</p>',
  text: 'Update: Important information...',
  priority: 'high',
  metadata: { campaign: 'newsletter' }
});
```

#### 发送模板电子邮件

```typescript
const result = await emailManager.sendTemplatedEmail(
  'welcome-email',
  { 
    user: { name: 'John Doe' },
    company: 'MyApp',
    confirmUrl: 'https://myapp.com/confirm?token=abc123'
  },
  ['newuser@example.com']
);
```

#### 计划电子邮件

```typescript
const scheduleTime = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours
const result = await emailManager.scheduleEmail({
  to: 'user@example.com',
  subject: 'Reminder',
  html: '<p>This is your scheduled reminder</p>'
}, scheduleTime);
```

### 模板管理

#### 创建模板

```typescript
const template = await emailManager.createTemplate({
  id: 'welcome-email',
  name: 'Welcome Email',
  subject: 'Welcome {{ user.name }}!',
  htmlTemplate: '<h1>Welcome {{ user.name }}!</h1><p>Thanks for joining {{ company }}!</p>',
  textTemplate: 'Welcome {{ user.name }}! Thanks for joining {{ company }}!',
  variables: [
    { name: 'user.name', type: 'string', required: true },
    { name: 'company', type: 'string', required: true }
  ],
  category: 'onboarding',
  version: '1.0.0',
  isActive: true
});
```

#### 列表模板

```typescript
const templates = await emailManager.listTemplates({
  page: 1,
  pageSize: 20,
  category: 'onboarding',
  active: true,
  search: 'welcome'
});
```

#### 更新模板

```typescript
const result = await emailManager.updateTemplate('welcome-email', {
  subject: 'Welcome to our platform, {{ user.name }}!',
  isActive: false
});
```

### 供应商管理

#### 添加提供者

```typescript
const result = await emailManager.addProvider({
  id: 'mailgun-backup',
  name: 'Mailgun Backup',
  type: 'mailgun',
  config: {
    apiKey: process.env.MAILGUN_API_KEY,
    domain: process.env.MAILGUN_DOMAIN
  },
  isActive: true,
  priority: 2,
  rateLimit: {
    maxPerMinute: 60,
    maxPerHour: 1000,
    maxPerDay: 10000
  }
});
```

#### 获取提供者状态

```typescript
const status = await emailManager.getProviderStatus('sendgrid');
console.log('Provider health:', status.isHealthy);
console.log('Current usage:', status.currentUsage);
```

#### 测试提供者连接

```typescript
const testResult = await emailManager.testConnection('sendgrid');
console.log('Connection test:', testResult.success, testResult.message);
```

### 分析和报告

#### 获取电子邮件统计

```typescript
const stats = await emailManager.getEmailStats('email-message-id');
console.log('Delivery rate:', stats.deliveryRate);
console.log('Open rate:', stats.openRate);
console.log('Click rate:', stats.clickRate);
```

#### 获取交付报告

```typescript
const report = await emailManager.getDeliveryReport({
  startDate: new Date('2024-01-01'),
  endDate: new Date('2024-01-31'),
  provider: 'sendgrid'
});
console.log('Total sent:', report.totalSent);
console.log('Delivery rate:', report.deliveryRate);
```

#### 获取分析摘要

```typescript
const summary = await emailManager.getAnalyticsSummary(30); // Last 30 days
console.log('Overview:', summary.overview);
console.log('Top providers:', summary.topProviders);
console.log('Daily stats:', summary.dailyStats);
```

### 时间安排管理

#### 取消已排定的电子邮件

```typescript
const result = await emailManager.cancelScheduledEmail('schedule-id');
console.log('Cancelled:', result.success);
```

## 配置

### 电子邮件管理员连接

```typescript
interface EmailManagerConfig {
  providers: EmailProvider[];          // Email provider configurations
  templates?: EmailTemplate[];         // Pre-loaded templates
  scheduling?: SchedulingConfig;       // Scheduler settings
  analytics?: AnalyticsConfig;         // Analytics settings
  retry?: RetryConfig;                // Retry policy settings
}
```

### 提供者配置

```typescript
interface EmailProvider {
  id: string;                         // Unique provider ID
  name: string;                       // Display name
  type: 'sendgrid' | 'mailgun' | 'ses' | 'smtp' | 'postmark';
  config: ProviderConfig;             // Provider-specific config
  isActive: boolean;                  // Enable/disable provider
  priority: number;                   // Provider priority (lower = higher priority)
  rateLimit?: RateLimit;              // Rate limiting settings
}
```

### 模板配置

```typescript
interface EmailTemplate {
  id: string;                         // Unique template ID
  name: string;                       // Display name
  subject: string;                    // Email subject (supports variables)
  htmlTemplate: string;               // HTML template content
  textTemplate?: string;              // Plain text template content
  variables: TemplateVariable[];      // Template variables
  category?: string;                  // Template category
  version: string;                    // Template version
  isActive: boolean;                  // Enable/disable template
}
```

## 提供者类型

### 发送Grid

```typescript
{
  type: 'sendgrid',
  config: {
    apiKey: 'your-sendgrid-api-key'
  }
}
```

### 邮件枪

```typescript
{
  type: 'mailgun',
  config: {
    apiKey: 'your-mailgun-api-key',
    domain: 'your-domain.mailgun.org'
  }
}
```

### 警报器

```typescript
{
  type: 'ses',
  config: {
    accessKeyId: 'your-access-key',
    secretAccessKey: 'your-secret-key',
    region: 'us-east-1'
  }
}
```

### SMTP 软件

```typescript
{
  type: 'smtp',
  config: {
    host: 'smtp.gmail.com',
    port: 587,
    secure: false,
    auth: {
      user: 'your-email@gmail.com',
      pass: 'your-password'
    }
  }
}
```

### 邮戳

```typescript
{
  type: 'postmark',
  config: {
    serverToken: 'your-postmark-server-token'
  }
}
```

## 模板变量

模板通过变量支持动态内容 :

```html
<!-- HTML Template -->
<h1>Welcome {{ user.name }}!</h1>
<p>Your account with {{ company }} is ready.</p>
<a href="{{ confirmUrl }}">Confirm Email</a>

<!-- Text Template -->
Welcome {{ user.name }}!
Your account with {{ company }} is ready.
Confirm your email: {{ confirmUrl }}
```

在模板配置中定义变量 :

```typescript
variables: [
  { name: 'user.name', type: 'string', required: true },
  { name: 'company', type: 'string', required: true },
  { name: 'confirmUrl', type: 'string', required: true }
]
```

## 处理错误

电子邮件管理器提供全面的错误处理 :

```typescript
const result = await emailManager.sendEmail(emailData);

if (!result.success) {
  console.error('Failed to send email:');
  result.errors?.forEach(error => {
    console.error(`${error.code}: ${error.message}`);
    if (error.recipient) {
      console.error(`Recipient: ${error.recipient}`);
    }
  });
}
```

## 事件跟踪

跟踪分析的电子邮件事件 :

```typescript
// Track email opened (typically from email tracking pixel)
emailManager.trackEmailEvent('opened', 'email-id', 'recipient@example.com');

// Track email clicked (typically from link tracking)
emailManager.trackEmailEvent('clicked', 'email-id', 'recipient@example.com', {
  url: 'https://example.com/clicked-link'
});

// Track email bounced (typically from webhook)
emailManager.trackEmailEvent('bounced', 'email-id', 'recipient@example.com', {
  reason: 'Invalid email address'
});
```

## Webhook 整合

与您的电子邮件提供商建立网络搜索以跟踪事件 :

```typescript
// Express.js webhook endpoint example
app.post('/webhook/sendgrid', (req, res) => {
  const events = req.body;
  
  events.forEach(event => {
    const { event: eventType, email, sg_message_id } = event;
    
    switch (eventType) {
      case 'delivered':
        emailManager.trackEmailEvent('delivered', sg_message_id, email);
        break;
      case 'open':
        emailManager.trackEmailEvent('opened', sg_message_id, email);
        break;
      case 'click':
        emailManager.trackEmailEvent('clicked', sg_message_id, email, { url: event.url });
        break;
      case 'bounce':
        emailManager.trackEmailEvent('bounced', sg_message_id, email, { reason: event.reason });
        break;
    }
  });
  
  res.status(200).send('OK');
});
```

## 魔法链接集成

生成安全认证链接 :

```typescript
// Generate magic link
const magicLink = await emailManager.generateMagicLink(
  'user@example.com',
  'login',
  { userId: '123', redirectUrl: '/dashboard' }
);

// Send magic link email
await emailManager.sendTemplatedEmail('magic-link-email', {
  magicLink: magicLink.url,
  user: { email: 'user@example.com' }
}, ['user@example.com']);

// Verify magic link (in your authentication endpoint)
const verification = await emailManager.verifyMagicLink(token);
if (verification.valid) {
  // Log user in
  console.log('User authenticated:', verification.payload);
}
```

## 性能优化

### 模板缓存

模板在编译后被缓存,以便更好的性能.

### 供应商集合

电子邮件提供者在可能情况下重复使用连接.

### 批处理

高效处理多封电子邮件:

```typescript
const emails = [
  { to: 'user1@example.com', subject: 'Email 1', html: '<p>Content 1</p>' },
  { to: 'user2@example.com', subject: 'Email 2', html: '<p>Content 2</p>' },
  // ... more emails
];

const results = await Promise.all(
  emails.map(email => emailManager.sendEmail(email))
);
```

### 限制费率

配置每个提供者的费率限制以遵守 API 限制 :

```typescript
{
  rateLimit: {
    maxPerMinute: 100,
    maxPerHour: 1000,
    maxPerDay: 10000
  }
}
```

## 系统状态

获得全面的系统统计:

```typescript
const stats = emailManager.getSystemStats();

console.log('Templates:', stats.templates);
// { total: 5, active: 4, inactive: 1, byCategory: { onboarding: 2, marketing: 3 } }

console.log('Providers:', stats.providers);
// { total: 2, active: 2, inactive: 0, byType: { sendgrid: 1, mailgun: 1 } }

console.log('Scheduler:', stats.scheduler);
// { isRunning: true, totalInQueue: 3, scheduled: 3, overdue: 0 }
```

## 关闭

总是正确关闭电子邮件管理器 :

```typescript
emailManager.shutdown();
```

这停止了调度器并清理了资源.

* * *

## 增强特性

这个 `EnhancedEmailManager` 扩展底线 `EmailManager` 包含日历邀请,批发,订阅管理,不订阅流量等. 所有增强功能都通过单一导入提供:

```typescript
import { EnhancedEmailManager, EnhancedEmailManagerConfig } from '@bernierllc/email-manager';
```

### 邀请

发送日历邀请(ICS)并取消作为电子邮件附件. 管理器使用 `@bernierllc/email-calendar` 包并自动附加.

#### 发送日历邀请

```typescript
import { EnhancedEmailManager, CalendarEvent } from '@bernierllc/email-manager';

const event: CalendarEvent = {
  uid: 'meeting-2025-q2@example.com',
  title: 'Q2 Business Review',
  description: 'Quarterly review of business metrics.',
  start: new Date('2025-07-15T14:00:00Z'),
  end: new Date('2025-07-15T15:30:00Z'),
  location: 'Conference Room A',
  organizer: { email: 'organizer@example.com', name: 'Alice Johnson' },
  attendees: [
    { email: 'bob@example.com', name: 'Bob Smith', role: 'REQ-PARTICIPANT' },
    { email: 'carol@example.com', name: 'Carol Lee', role: 'OPT-PARTICIPANT' },
  ],
};

const result = await manager.sendCalendarInvite(
  event,
  ['bob@example.com', 'carol@example.com'],
);

console.log('Invite sent:', result.success);
```

您可以自定义主题和身体 :

```typescript
const result = await manager.sendCalendarInvite(event, recipients, {
  subject: 'You are invited: Q2 Business Review',
  htmlBody: '<h2>Q2 Review</h2><p>Please join us for the quarterly review.</p>',
  textBody: 'Please join us for the Q2 quarterly review.',
  metadata: { campaign: 'internal-meetings' },
});
```

#### 取消日历事件

```typescript
import { CalendarAttendee } from '@bernierllc/email-manager';

const organizer: CalendarAttendee = { email: 'organizer@example.com', name: 'Alice' };
const attendees: CalendarAttendee[] = [
  { email: 'bob@example.com', name: 'Bob' },
  { email: 'carol@example.com', name: 'Carol' },
];

const result = await manager.sendCalendarCancel(
  'meeting-2025-q2@example.com', // UID of the original event
  organizer,
  attendees,
  {
    subject: 'Cancelled: Q2 Business Review',
    htmlBody: '<p>The Q2 Business Review has been cancelled.</p>',
  },
);
```

> 见 [`examples/calendar-invites.ts`](https://npmcn.com/package/%40bernierllc/email-manager/examples/calendar-invites.ts) 是一个完整的范例.

* * *

### 批量发送

发送大量带有内置货币控制的电子邮件, 速率限制, 重试逻辑和进度跟踪 。 电源 `@bernierllc/email-batch-sender`。 。 。 .

#### 基本批发

```typescript
import { BatchEmailInput } from '@bernierllc/email-manager';

const emails: BatchEmailInput[] = [
  {
    toEmail: 'alice@example.com',
    subject: 'Newsletter - July',
    htmlContent: '<h1>Newsletter</h1><p>Hello Alice...</p>',
    textContent: 'Newsletter\n\nHello Alice...',
  },
  {
    toEmail: 'bob@example.com',
    subject: 'Newsletter - July',
    htmlContent: '<h1>Newsletter</h1><p>Hello Bob...</p>',
  },
];

const result = await manager.sendBatch(emails);
console.log(`Sent: ${result.succeeded}/${result.total}, Failed: ${result.failed}`);
```

#### 批量发送, 限制费率并重试

```typescript
import { BatchSenderOptions } from '@bernierllc/email-manager';

const options: BatchSenderOptions = {
  concurrency: 5,               // Up to 5 emails in parallel
  rateLimit: {
    maxPerSecond: 10,            // Respect provider rate limits
  },
  retry: {
    maxRetries: 3,               // Retry failed sends
    initialDelayMs: 1000,        // 1 second initial delay
    backoffMultiplier: 2,        // Exponential backoff
  },
  failureStrategy: 'continue',  // Keep sending even if some fail
};

const result = await manager.sendBatch(emails, options);
```

#### 批次随进度跟踪发送

```typescript
const result = await manager.sendBatch(emails, {
  concurrency: 3,
  onProgress: (progress) => {
    const pct = ((progress.completed / progress.total) * 100).toFixed(0);
    console.log(`Progress: ${pct}% - ${progress.succeeded} sent, ${progress.failed} failed`);
  },
});
```

#### 失败时中止

对于不能接受部分发送的关键邮件:

```typescript
const result = await manager.sendBatch(criticalEmails, {
  concurrency: 1,
  failureStrategy: 'abort',  // Stop immediately on first failure
  retry: { maxRetries: 5 },
});

if (result.aborted) {
  console.error('Batch was aborted due to a failure');
}
```

> 见 [`examples/batch-sending.ts`](https://npmcn.com/package/%40bernierllc/email-manager/examples/batch-sending.ts) 用于完整的例子.

* * *

### 订阅管理

管理订阅者列表,添加/移动订阅者,并处理批量进口. 订阅系统使用 `@bernierllc/email-subscription` 在引擎盖下.

#### 创建订阅者列表

```typescript
const newsletter = await manager.createSubscriberList('Monthly Newsletter', {
  description: 'Monthly product newsletter subscribers',
  metadata: { category: 'marketing' },
});

console.log('List ID:', newsletter.id);
```

#### 添加订阅者

```typescript
// Individual subscriber
await manager.addSubscriber(newsletter.id, {
  email: 'alice@example.com',
  name: 'Alice Johnson',
});

// Bulk add (skips duplicates and suppressed emails)
const result = await manager.addSubscribers(newsletter.id, [
  { email: 'user1@example.com', name: 'User One' },
  { email: 'user2@example.com', name: 'User Two' },
  { email: 'user3@example.com', name: 'User Three' },
]);

console.log(`Added: ${result.added}, Skipped: ${result.skipped}`);
```

#### 向上查找并删除订阅者

```typescript
// Look up a subscriber
const subscriber = await manager.getSubscriber(newsletter.id, 'alice@example.com');
if (subscriber) {
  console.log('Status:', subscriber.status);
}

// Remove a subscriber
const removed = await manager.removeSubscriber(newsletter.id, 'alice@example.com');
```

#### 删除列表

```typescript
const deleted = await manager.deleteSubscriberList(newsletter.id);
```

* * *

### 取消订阅流程

生成已签名的未订阅 URL 并处理未订阅请求 。 要求 `subscription.unsubscribe` 配置 .

#### 配置

```typescript
const config: EnhancedEmailManagerConfig = {
  providers: [/* ... */],
  subscription: {
    enabled: true,
    unsubscribe: {
      baseUrl: 'https://example.com/unsubscribe',
      secret: process.env.UNSUBSCRIBE_SECRET!,
      expiresIn: 30 * 24 * 60 * 60, // 30 days
    },
  },
};
```

#### 生成未订阅的 URL

```typescript
const url = manager.generateUnsubscribeUrl('alice@example.com', listId);
// Returns: https://example.com/unsubscribe?token=<signed-jwt>
```

#### 取消订阅请求

在您的网络服务器未订阅端点 :

```typescript
app.get('/unsubscribe', async (req, res) => {
  const token = req.query.token as string;

  try {
    await manager.processUnsubscribe(token);
    res.send('You have been unsubscribed successfully.');
  } catch (error) {
    res.status(400).send('Invalid or expired unsubscribe link.');
  }
});
```

#### 用列表- 取消订阅信头发送电子邮件

自动生成并附加 RFC 2369 / RFC 8058 `List-Unsubscribe` 标题 :

```typescript
const result = await manager.sendWithUnsubscribe(
  {
    to: 'alice@example.com',
    subject: 'Monthly Newsletter',
    html: '<p>Newsletter content...</p>',
  },
  listId,                  // Subscriber list ID
  'alice@example.com',     // Recipient for token generation
  true,                    // Enable one-click unsubscribe (RFC 8058)
);
```

> 见 [`examples/subscription-management.ts`](https://npmcn.com/package/%40bernierllc/email-manager/examples/subscription-management.ts) 整个生命周期.

* * *

### 取缔

检查发送前是否关闭电子邮件地址 。 当订阅者不订阅或处理回弹/投诉时,电子邮件就会被压制.

```typescript
// Check global suppression
const isSuppressed = await manager.isSuppressed('alice@example.com');

// Check list-specific suppression
const isListSuppressed = await manager.isSuppressed('alice@example.com', listId);

if (isSuppressed) {
  console.log('Skipping send - email is suppressed');
}
```

* * *

### 自定义订阅存储器

默认情况下,管理者会使用内存订阅商店. 生产时,取而代之的是数据库支持的执行:

```typescript
import { SubscriptionStore } from '@bernierllc/email-manager';

class DatabaseSubscriptionStore implements SubscriptionStore {
  // Implement all SubscriptionStore methods using your database
  // (createList, getList, addSubscriber, etc.)
}

const store = new DatabaseSubscriptionStore();
manager.setSubscriptionStore(store);
```

* * *

### 自定义信头

添加用于线程的自定义电子邮件信头、 读取收据和其他目的, 将它们包含到 `metadata.headers` 字段.

#### 电子邮件线索

```typescript
const result = await manager.sendEmail({
  to: 'colleague@example.com',
  subject: 'Re: Project Discussion',
  html: '<p>I agree with the proposed approach.</p>',
  metadata: {
    headers: {
      'In-Reply-To': '<original-message-id@example.com>',
      'References': '<original-message-id@example.com>',
    },
  },
});
```

#### 列表- 未订阅信头( 单独)

使用 `createListUnsubscribeHeaders` 工具栏直接 :

```typescript
import { createListUnsubscribeHeaders } from '@bernierllc/email-manager';

const headers = createListUnsubscribeHeaders(
  'https://example.com/unsubscribe?id=123',   // HTTPS unsubscribe URL
  'mailto:unsub@example.com?subject=unsub',    // Optional mailto fallback
  true,                                         // One-click unsubscribe (RFC 8058)
);

const result = await manager.sendEmail({
  to: 'subscriber@example.com',
  subject: 'Weekly Digest',
  html: '<p>Your digest...</p>',
  metadata: { headers },
});
```

#### MDN( 读取) 请求

```typescript
const result = await manager.sendEmail({
  to: 'recipient@example.com',
  subject: 'Contract for Review',
  html: '<p>Please confirm receipt of the attached contract.</p>',
  metadata: {
    headers: {
      'Disposition-Notification-To': 'sender@example.com',
    },
  },
});
```

> 见 [`examples/attachments-and-headers.ts`](https://npmcn.com/package/%40bernierllc/email-manager/examples/attachments-and-headers.ts) 用于完整的例子.

* * *

### 附录

发送带有文件附件的邮件, 内置图像, 或者两者兼有 .

#### 文件附件

```typescript
const result = await manager.sendEmail({
  to: 'recipient@example.com',
  subject: 'Report Attached',
  html: '<p>Please find the report attached.</p>',
  attachments: [
    {
      filename: 'report.pdf',
      content: fs.readFileSync('/path/to/report.pdf'),
      contentType: 'application/pdf',
    },
  ],
});
```

#### 字符串内容附件

```typescript
const csvData = 'Name,Email\nAlice,alice@example.com\nBob,bob@example.com\n';

const result = await manager.sendEmail({
  to: 'manager@example.com',
  subject: 'User Export',
  html: '<p>User export attached.</p>',
  attachments: [
    {
      filename: 'users.csv',
      content: csvData,  // String content is also supported
      contentType: 'text/csv',
    },
  ],
});
```

#### 内嵌/ 内嵌图像

使用内容ID( CID) 的内置引用图像 :

```typescript
const result = await manager.sendEmail({
  to: 'customer@example.com',
  subject: 'Order Confirmation',
  html: `
    <img src="cid:company-logo" alt="Logo" />
    <h2>Order Confirmed!</h2>
  `,
  attachments: [
    {
      filename: 'logo.png',
      content: fs.readFileSync('/path/to/logo.png'),
      contentType: 'image/png',
      contentDisposition: 'inline',
      cid: 'company-logo',  // Matches src="cid:company-logo" in HTML
    },
  ],
});
```

#### 多个附件

```typescript
const result = await manager.sendEmail({
  to: 'team@example.com',
  subject: 'Brand Kit Assets',
  html: '<p>Attached are the brand assets.</p>',
  attachments: [
    {
      filename: 'guidelines.pdf',
      content: fs.readFileSync('/path/to/guidelines.pdf'),
      contentType: 'application/pdf',
    },
    {
      filename: 'logo.png',
      content: fs.readFileSync('/path/to/logo.png'),
      contentType: 'image/png',
    },
    {
      filename: 'palette.json',
      content: JSON.stringify({ primary: '#0066CC' }, null, 2),
      contentType: 'application/json',
    },
  ],
});
```

> 见 [`examples/attachments-and-headers.ts`](https://npmcn.com/package/%40bernierllc/email-manager/examples/attachments-and-headers.ts) 用于完整的例子.

* * *

## 能力矩阵和智能运行

电子邮件管理器包括一个完整的能力矩阵,将每个功能映射给每个提供者,从而能够作出智能的路由决定和优雅地退化.

### 能力矩阵

每个特性按提供者分类,有四种来源类型之一:

| 来源 | 含义 |
| --- | --- |
| `provider` | 由电子邮件提供者的 API 原生支持 |
| `platform` | 由平台执行(在当地填充) |
| `enhanced` | 建在具有附加值的原始供应商之上 |
| `unsupported` | 此提供者不可用 |

#### 提供者特性支持

| 特性 | 发送Grid | 邮件枪 | 邮戳 | 用户 | SMTP 软件 |
| --- | --- | --- | --- | --- | --- |
| 发送电子邮件 | 提供者 | 提供者 | 提供者 | 提供者 | 提供者 |
| 批发 | 提供者 | 提供者 | 提供者 | 提供者 | 平台 |
| 供应商模板 | 提供者 | 提供者 | 提供者 | 提供者 | 不支持 |
| 本地模板 | 平台 | 平台 | 平台 | 平台 | 平台 |
| 日历邀请 | 平台 | 平台 | 平台 | 平台 | 平台 |
| 日历事件Mgmt | 平台 | 平台 | 平台 | 平台 | 平台 |
| 网络用户接收 | 提供者 | 提供者 | 提供者 | 提供者 | 不支持 |
| 网点规范化 | 增强 | 增强 | 增强 | 增强 | 不支持 |
| 交付 跟踪 | 提供者 | 提供者 | 提供者 | 提供者 | 不支持 |
| 正在输入电子邮件 | 增强 | 增强 | 增强 | 增强 | 不支持 |
| 订阅Mgmt | 增强 | 增强 | 平台 | 平台 | 平台 |
| 压制 | 提供者 | 提供者 | 提供者 | 提供者 | 平台 |
| 未订阅 UrlGeneration | 平台 | 平台 | 平台 | 平台 | 平台 |
| 预定发送 | 提供者 | 提供者 | 平台 | 平台 | 平台 |
| 打开点击跟踪 | 提供者 | 提供者 | 供应商\* | 不支持 | 不支持 |
| 自动跟踪 | 提供者 | 不支持 | 不支持 | 不支持 | 不支持 |
| 电子邮件连接 | 平台 | 平台 | 平台 | 平台 | 平台 |
| 电子邮件页眉Mgmt | 平台 | 平台 | 平台 | 平台 | 平台 |
| 附录 | 提供者 | 提供者 | 提供者 | 提供者 | 提供者 |
| 高级随附处理 | 平台 | 平台 | 平台 | 平台 | 平台 |
| dkimSpf 数据 | 提供者 | 提供者 | 提供者 | 提供者 | 不支持 |
| 链接显示 | 提供者 | 提供者 | 不支持 | 不支持 | 不支持 |
| 复试 | 平台 | 平台 | 平台 | 平台 | 平台 |
| 多服务失败 | 平台 | 平台 | 平台 | 平台 | 平台 |

\* 邮政标记支持每个消息的开放和链接跟踪; `TrackOpens: false` 在服务器级别上打开跟踪时被忽略.

特定提供者的显著限制:

-   **发送Grid** `scheduledSend`: 72小时最大排程窗口
-   **邮件枪** `scheduledSend`: 3天最大排程窗口
-   **用户** `webhooksReceive` 编号 : `deliveryTracking`: 需要 SNS 专题配置

### 运行配置

能力感知路由是选入. 添加一个 `routing` 区域到您的配置 :

```typescript
import { EmailManager, EmailManagerConfig } from '@bernierllc/email-manager';

const config: EmailManagerConfig = {
  providers: [
    { id: 'sg', name: 'SendGrid', type: 'sendgrid', config: { apiKey: '...' }, isActive: true, priority: 1 },
    { id: 'mg', name: 'Mailgun', type: 'mailgun', config: { apiKey: '...', domain: '...' }, isActive: true, priority: 2 },
  ],
  routing: {
    strategy: 'primary-failover',
    featureOverrides: {
      // Always use platform implementation for local templates
      localTemplates: { behavior: 'platform-always' },
      // Throw an error if no native provider supports the feature
      openClickTracking: { behavior: 'error' },
    },
  },
  degradation: {
    logLevel: 'warn',
    includeDocLinks: true,
    docsBaseUrl: 'https://docs.example.com/email',
  },
};

const manager = new EmailManager(config);
```

#### 特性覆盖行为

| 行为 | 说明 |
| --- | --- |
| `native-first` | (默认) 优先提供本地支持或增强支持的供应商; 如果找不到, 则返回平台 |
| `platform-always` | 总是使用平台执行, 即使提供者在本地支持它 |
| `error` | 掷出 `FeatureUnsupportedError` 如果没有本地或强化支持的提供者 |

### 退化行为

当一个特性通过平台多填充(非原生)被路由给提供者时,系统记录降解信息:

-   **`platform` 源特性** (例如,SMTP) `batchSend`:电子邮件按顺序发送,而不是按真实批次发送. 这个 `SendResult.routing` 字段显示 `degraded: true` 带有 `degradationReason`。 。 。 .
-   **`unsupported` 特性** (例如,SMTP) `webhooksReceive`:路由器完全跳过提供者,按优先级顺序尝试下一个. 如果没有提供者支持该特性, a `FeatureUnsupportedError` 被抛出.
-   **退化伐木**: 由 `degradation.logLevel` (单位:千美元)`'silent'` | `'info'` | `'warn'` | `'error'`) (中文(简体) ). 何时 `includeDocLinks` 实值 `true`,日志信息包括与降解文件的链接.

### Redis 解析器设置

默认情况下,能力矩阵会从内映快照中解决. 对于跨多个实例的共享或动态能力数据,使用Redis后置的解析器:

```bash
# Set the environment variable to enable Redis resolver auto-detection
export EMAIL_MANAGER_REDIS_URL="redis://localhost:6379"
```

工厂`createCapabilityResolver`)自动检测环境变量并创建一个 `SafeCapabilityResolver` 将Redis解析器包裹在记忆回落中 若为 `ioredis` 没有安装或 Redis 无法使用, 它会悄悄地回到内膜解析器.

#### Redis 解析器选项

```typescript
import { createCapabilityResolver } from '@bernierllc/email-manager';

const resolver = await createCapabilityResolver({
  namespace: 'myapp:capabilities', // Redis key namespace (default: 'email-manager:capabilities')
  ttl: 3600,                       // Cache TTL in seconds (default: varies by implementation)
});
```

您也可以提供自己的解析器执行:

```typescript
const config: EmailManagerConfig = {
  providers: [/* ... */],
  routing: {
    strategy: 'primary-failover',
    capabilityResolver: myCustomResolver, // Must implement CapabilityResolver interface
  },
};
```

### 回复中的搜索元数据

当路由活动时, `SendResult` 包含a `routing` 字段 :

```typescript
const result = await manager.sendEmail(emailData);

if (result.routing) {
  console.log('Provider used:', result.routing.provider);
  console.log('Feature:', result.routing.feature);
  console.log('Source:', result.routing.source);       // 'provider' | 'platform' | 'enhanced' | 'unsupported'
  console.log('Degraded:', result.routing.degraded);   // true if platform polyfill was used
  console.log('Reason:', result.routing.degradationReason);
  console.log('Tried:', result.routing.attemptedProviders); // providers checked before selecting
}
```

这个 `RoutingMetadata` 接口 :

```typescript
interface RoutingMetadata {
  provider: string;
  feature: string;
  source: 'provider' | 'platform' | 'enhanced' | 'unsupported';
  degraded: boolean;
  degradationReason?: string;
  attemptedProviders?: string[];
}
```

### V.4.x的迁移指南

能力矩阵和路由系统完全后向相容. 现有代码继续工作,没有变化:

-   **没有路由配置**: 当 `routing` 在配置中被省略,管理器使用与之前相同的提供者选择逻辑(基于优先级的故障).
-   **无降解配置**: 当 `degradation` 不记录降解事件.
-   **选入**:为了实现能感知到的路由,增加一个 `routing` 区域到您的配置。 这个 `RoutingMetadata` 打开 `SendResult` 仅在路由活动时才会出现.
-   **无新的依赖关系**: Redis 解析器是可选的,只有在 `EMAIL_MANAGER_REDIS_URL` 设置和 `ioredis` 已安装.

* * *

## 再出口类型

为了方便起见,电子邮件管理者从它的子包中再出口类型和公用事业,因此消费者不需要直接依赖:

| 软件包 | 再出口物品 |
| --- | --- |
| `@bernierllc/email-calendar` | `CalendarEvent`, (中文(简体) ), `CalendarAttendee`, (中文(简体) ), `CalendarMethod`, (中文(简体) ), `createCalendarInvite`, (中文(简体) ), `createCalendarCancel`, (中文(简体) ), `toCalendarAttachment` |
| `@bernierllc/email-batch-sender` | `BatchSenderOptions`, (中文(简体) ), `BatchResult`, (中文(简体) ), `BatchEmailInput`, (中文(简体) ), `BatchProgress`, (中文(简体) ), `BatchSender`, (中文(简体) ), `createBatchSender` |
| `@bernierllc/email-subscription` | `SubscriberList`, (中文(简体) ), `Subscriber`, (中文(简体) ), `SubscriptionStore`, (中文(简体) ), `AddSubscriberInput`, (中文(简体) ), `CreateListOptions`, (中文(简体) ), `BulkAddResult`, (中文(简体) ), `UnsubscribeManager`, (中文(简体) ), `SuppressionManager`, (中文(简体) ), `InMemorySubscriptionStore` |
| `@bernierllc/email-headers` | `EmailHeaders`, (中文(简体) ), `ThreadingHeaders`, (中文(简体) ), `ListUnsubscribeHeaders`, (中文(简体) ), `createListUnsubscribeHeaders` |
| `@bernierllc/email-attachments` | `AttachmentInput`, (中文(简体) ), `AttachmentLimits`, (中文(简体) ), `AttachmentValidationResult` |

## 许可证

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

## 另见

-   [@bernierllc/电子邮件发送器](https://npmcn.com/package/%40bernierllc/email-sender) - 核心电子邮件发送功能
-   [@ bernierllc/ template- 引擎](https://npmcn.com/package/%40bernierllc/template-engine) - 模板渲染引擎
-   [@bernierllc/魔法链接](https://npmcn.com/package/%40bernierllc/magic-link) - 安全代币生成

## 常见问题

### @bernierllc/email-manager 是什么？

完整的电子邮件管理套件,包含模板管理,调度,分析,以及提供者的管弦乐\(仅节点\.js - 浏览器使用@bernierllc/电子邮件-manager-客户端\)

### 如何安装 @bernierllc/email-manager？

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

### @bernierllc/email-manager 支持 TypeScript 吗？

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

### @bernierllc/email-manager 支持 ESM 还是 CommonJS？

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

### @bernierllc/email-manager 可以商用吗？

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

### @bernierllc/email-manager 的下载量有多少？

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

### @bernierllc/email-manager 还在维护吗？

最新版本 0\.12\.3 发布于 2026/11/05（3 天前）；至今共发布 38 个版本，其中过去 12 个月发布了 37 个；首次发布于 2025/08/22。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

