@bernierllc/电子邮件管理员
一个全面的电子邮件管理服务,负责管理电子邮件发送、模板管理、时间安排和分析。 此服务与 @bernierllc/email-sender, (中文(简体) ), @bernierllc/template-engine,以及 @bernierllc/magic-link 提供完整的电子邮件解决方案.
只有节点.js
此软件包是 Node.js- only 并且由于Node.js的依赖关系(nodemailer等)而无法被捆绑用于浏览器.
用于浏览器/前端应用程序,使用时 @bernierllc/email-manager-client 相反,它通过HTTP呼叫提供相同的API.
特征
🚀 电子邮件管弦乐团
- 多供应商支助 自动失效
- 基于模板的电子邮件 有动态内容渲染
- 电子邮件时间安排 重试逻辑
- 批量电子邮件处理 用于大宗业务
📝 模板管理
- CRUD 操作 电子邮件模板
- 模板版本 生命周期管理
- 变量验证 和语法检查
- 基于职类的组织
🔧 供应商管理
- 多提供者配置 (SendGrid、Mailgun、AWS SES、SMTP、邮戳)
- 提供者健康监测 和状态跟踪
- 限制费率 和使用情况跟踪
- 自动失效 提供者之间
📊 分析和报告
- 电子邮件性能跟踪 (打开,点击,弹出)
- 交付报告 弹出分析
- 供应商业绩衡量标准
- 历史数据 和趋势分析
⏰ 日程安排系统
- 基于队列的排程 准确的时间
- 重试逻辑 交付失败
- 附表管理 (取消,修改)
- 背景处理 自动清理
安装
npm install @bernierllc/email-manager
依赖关系
这个软件包需要以下伯尼RLC核心软件包:
npm install @bernierllc/email-sender @bernierllc/template-engine @bernierllc/magic-link
快速启动
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: '[email protected]',
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
电子邮件操作
发送电子邮件
const result = await emailManager.sendEmail({
to: ['[email protected]', '[email protected]'],
cc: ['[email protected]'],
subject: 'Important Update',
html: '<h1>Update</h1><p>Important information...</p>',
text: 'Update: Important information...',
priority: 'high',
metadata: { campaign: 'newsletter' }
});
发送模板电子邮件
const result = await emailManager.sendTemplatedEmail(
'welcome-email',
{
user: { name: 'John Doe' },
company: 'MyApp',
confirmUrl: 'https://myapp.com/confirm?token=abc123'
},
['[email protected]']
);
计划电子邮件
const scheduleTime = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours
const result = await emailManager.scheduleEmail({
to: '[email protected]',
subject: 'Reminder',
html: '<p>This is your scheduled reminder</p>'
}, scheduleTime);
模板管理
创建模板
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
});
列表模板
const templates = await emailManager.listTemplates({
page: 1,
pageSize: 20,
category: 'onboarding',
active: true,
search: 'welcome'
});
更新模板
const result = await emailManager.updateTemplate('welcome-email', {
subject: 'Welcome to our platform, {{ user.name }}!',
isActive: false
});
供应商管理
添加提供者
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
}
});
获取提供者状态
const status = await emailManager.getProviderStatus('sendgrid');
console.log('Provider health:', status.isHealthy);
console.log('Current usage:', status.currentUsage);
测试提供者连接
const testResult = await emailManager.testConnection('sendgrid');
console.log('Connection test:', testResult.success, testResult.message);
分析和报告
获取电子邮件统计
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);
获取交付报告
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);
获取分析摘要
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);
时间安排管理
取消已排定的电子邮件
const result = await emailManager.cancelScheduledEmail('schedule-id');
console.log('Cancelled:', result.success);
配置
电子邮件管理员连接
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
}
提供者配置
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
}
模板配置
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
{
type: 'sendgrid',
config: {
apiKey: 'your-sendgrid-api-key'
}
}
邮件枪
{
type: 'mailgun',
config: {
apiKey: 'your-mailgun-api-key',
domain: 'your-domain.mailgun.org'
}
}
警报器
{
type: 'ses',
config: {
accessKeyId: 'your-access-key',
secretAccessKey: 'your-secret-key',
region: 'us-east-1'
}
}
SMTP 软件
{
type: 'smtp',
config: {
host: 'smtp.gmail.com',
port: 587,
secure: false,
auth: {
user: '[email protected]',
pass: 'your-password'
}
}
}
邮戳
{
type: 'postmark',
config: {
serverToken: 'your-postmark-server-token'
}
}
模板变量
模板通过变量支持动态内容 :
<!-- 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 }}
在模板配置中定义变量 :
variables: [
{ name: 'user.name', type: 'string', required: true },
{ name: 'company', type: 'string', required: true },
{ name: 'confirmUrl', type: 'string', required: true }
]
处理错误
电子邮件管理器提供全面的错误处理 :
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}`);
}
});
}
事件跟踪
跟踪分析的电子邮件事件 :
// Track email opened (typically from email tracking pixel)
emailManager.trackEmailEvent('opened', 'email-id', '[email protected]');
// Track email clicked (typically from link tracking)
emailManager.trackEmailEvent('clicked', 'email-id', '[email protected]', {
url: 'https://example.com/clicked-link'
});
// Track email bounced (typically from webhook)
emailManager.trackEmailEvent('bounced', 'email-id', '[email protected]', {
reason: 'Invalid email address'
});
Webhook 整合
与您的电子邮件提供商建立网络搜索以跟踪事件 :
// 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');
});
魔法链接集成
生成安全认证链接 :
// Generate magic link
const magicLink = await emailManager.generateMagicLink(
'[email protected]',
'login',
{ userId: '123', redirectUrl: '/dashboard' }
);
// Send magic link email
await emailManager.sendTemplatedEmail('magic-link-email', {
magicLink: magicLink.url,
user: { email: '[email protected]' }
}, ['[email protected]']);
// 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);
}
性能优化
模板缓存
模板在编译后被缓存,以便更好的性能.
供应商集合
电子邮件提供者在可能情况下重复使用连接.
批处理
高效处理多封电子邮件:
const emails = [
{ to: '[email protected]', subject: 'Email 1', html: '<p>Content 1</p>' },
{ to: '[email protected]', subject: 'Email 2', html: '<p>Content 2</p>' },
// ... more emails
];
const results = await Promise.all(
emails.map(email => emailManager.sendEmail(email))
);
限制费率
配置每个提供者的费率限制以遵守 API 限制 :
{
rateLimit: {
maxPerMinute: 100,
maxPerHour: 1000,
maxPerDay: 10000
}
}
系统状态
获得全面的系统统计:
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 }
关闭
总是正确关闭电子邮件管理器 :
emailManager.shutdown();
这停止了调度器并清理了资源.
增强特性
这个 EnhancedEmailManager 扩展底线 EmailManager 包含日历邀请,批发,订阅管理,不订阅流量等. 所有增强功能都通过单一导入提供:
import { EnhancedEmailManager, EnhancedEmailManagerConfig } from '@bernierllc/email-manager';
邀请
发送日历邀请(ICS)并取消作为电子邮件附件. 管理器使用 @bernierllc/email-calendar 包并自动附加.
发送日历邀请
import { EnhancedEmailManager, CalendarEvent } from '@bernierllc/email-manager';
const event: CalendarEvent = {
uid: '[email protected]',
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: '[email protected]', name: 'Alice Johnson' },
attendees: [
{ email: '[email protected]', name: 'Bob Smith', role: 'REQ-PARTICIPANT' },
{ email: '[email protected]', name: 'Carol Lee', role: 'OPT-PARTICIPANT' },
],
};
const result = await manager.sendCalendarInvite(
event,
['[email protected]', '[email protected]'],
);
console.log('Invite sent:', result.success);
您可以自定义主题和身体 :
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' },
});
取消日历事件
import { CalendarAttendee } from '@bernierllc/email-manager';
const organizer: CalendarAttendee = { email: '[email protected]', name: 'Alice' };
const attendees: CalendarAttendee[] = [
{ email: '[email protected]', name: 'Bob' },
{ email: '[email protected]', name: 'Carol' },
];
const result = await manager.sendCalendarCancel(
'[email protected]', // 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是一个完整的范例.
批量发送
发送大量带有内置货币控制的电子邮件, 速率限制, 重试逻辑和进度跟踪 。 电源 @bernierllc/email-batch-sender。 。 。 .
基本批发
import { BatchEmailInput } from '@bernierllc/email-manager';
const emails: BatchEmailInput[] = [
{
toEmail: '[email protected]',
subject: 'Newsletter - July',
htmlContent: '<h1>Newsletter</h1><p>Hello Alice...</p>',
textContent: 'Newsletter\n\nHello Alice...',
},
{
toEmail: '[email protected]',
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}`);
批量发送, 限制费率并重试
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);
批次随进度跟踪发送
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`);
},
});
失败时中止
对于不能接受部分发送的关键邮件:
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用于完整的例子.
订阅管理
管理订阅者列表,添加/移动订阅者,并处理批量进口. 订阅系统使用 @bernierllc/email-subscription 在引擎盖下.
创建订阅者列表
const newsletter = await manager.createSubscriberList('Monthly Newsletter', {
description: 'Monthly product newsletter subscribers',
metadata: { category: 'marketing' },
});
console.log('List ID:', newsletter.id);
添加订阅者
// Individual subscriber
await manager.addSubscriber(newsletter.id, {
email: '[email protected]',
name: 'Alice Johnson',
});
// Bulk add (skips duplicates and suppressed emails)
const result = await manager.addSubscribers(newsletter.id, [
{ email: '[email protected]', name: 'User One' },
{ email: '[email protected]', name: 'User Two' },
{ email: '[email protected]', name: 'User Three' },
]);
console.log(`Added: ${result.added}, Skipped: ${result.skipped}`);
向上查找并删除订阅者
// Look up a subscriber
const subscriber = await manager.getSubscriber(newsletter.id, '[email protected]');
if (subscriber) {
console.log('Status:', subscriber.status);
}
// Remove a subscriber
const removed = await manager.removeSubscriber(newsletter.id, '[email protected]');
删除列表
const deleted = await manager.deleteSubscriberList(newsletter.id);
取消订阅流程
生成已签名的未订阅 URL 并处理未订阅请求 。 要求 subscription.unsubscribe 配置 .
配置
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
const url = manager.generateUnsubscribeUrl('[email protected]', listId);
// Returns: https://example.com/unsubscribe?token=<signed-jwt>
取消订阅请求
在您的网络服务器未订阅端点 :
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 标题 :
const result = await manager.sendWithUnsubscribe(
{
to: '[email protected]',
subject: 'Monthly Newsletter',
html: '<p>Newsletter content...</p>',
},
listId, // Subscriber list ID
'[email protected]', // Recipient for token generation
true, // Enable one-click unsubscribe (RFC 8058)
);
见
examples/subscription-management.ts整个生命周期.
取缔
检查发送前是否关闭电子邮件地址 。 当订阅者不订阅或处理回弹/投诉时,电子邮件就会被压制.
// Check global suppression
const isSuppressed = await manager.isSuppressed('[email protected]');
// Check list-specific suppression
const isListSuppressed = await manager.isSuppressed('[email protected]', listId);
if (isSuppressed) {
console.log('Skipping send - email is suppressed');
}
自定义订阅存储器
默认情况下,管理者会使用内存订阅商店. 生产时,取而代之的是数据库支持的执行:
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 字段.
电子邮件线索
const result = await manager.sendEmail({
to: '[email protected]',
subject: 'Re: Project Discussion',
html: '<p>I agree with the proposed approach.</p>',
metadata: {
headers: {
'In-Reply-To': '<[email protected]>',
'References': '<[email protected]>',
},
},
});
列表- 未订阅信头( 单独)
使用 createListUnsubscribeHeaders 工具栏直接 :
import { createListUnsubscribeHeaders } from '@bernierllc/email-manager';
const headers = createListUnsubscribeHeaders(
'https://example.com/unsubscribe?id=123', // HTTPS unsubscribe URL
'mailto:[email protected]?subject=unsub', // Optional mailto fallback
true, // One-click unsubscribe (RFC 8058)
);
const result = await manager.sendEmail({
to: '[email protected]',
subject: 'Weekly Digest',
html: '<p>Your digest...</p>',
metadata: { headers },
});
MDN( 读取) 请求
const result = await manager.sendEmail({
to: '[email protected]',
subject: 'Contract for Review',
html: '<p>Please confirm receipt of the attached contract.</p>',
metadata: {
headers: {
'Disposition-Notification-To': '[email protected]',
},
},
});
见
examples/attachments-and-headers.ts用于完整的例子.
附录
发送带有文件附件的邮件, 内置图像, 或者两者兼有 .
文件附件
const result = await manager.sendEmail({
to: '[email protected]',
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',
},
],
});
字符串内容附件
const csvData = 'Name,Email\nAlice,[email protected]\nBob,[email protected]\n';
const result = await manager.sendEmail({
to: '[email protected]',
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) 的内置引用图像 :
const result = await manager.sendEmail({
to: '[email protected]',
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
},
],
});
多个附件
const result = await manager.sendEmail({
to: '[email protected]',
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用于完整的例子.
能力矩阵和智能运行
电子邮件管理器包括一个完整的能力矩阵,将每个功能映射给每个提供者,从而能够作出智能的路由决定和优雅地退化.
能力矩阵
每个特性按提供者分类,有四种来源类型之一:
| 来源 | 含义 |
|---|---|
provider | 由电子邮件提供者的 API 原生支持 |
platform | 由平台执行(在当地填充) |
enhanced | 建在具有附加值的原始供应商之上 |
unsupported | 此提供者不可用 |
提供者特性支持
| 特性 | 发送Grid | 邮件枪 | 邮戳 | 用户 | SMTP 软件 |
|---|---|---|---|---|---|
| 发送电子邮件 | 提供者 | 提供者 | 提供者 | 提供者 | 提供者 |
| 批发 | 提供者 | 提供者 | 提供者 | 提供者 | 平台 |
| 供应商模板 | 提供者 | 提供者 | 提供者 | 提供者 | 不支持 |
| 本地模板 | 平台 | 平台 | 平台 | 平台 | 平台 |
| 日历邀请 | 平台 | 平台 | 平台 | 平台 | 平台 |
| 日历事件Mgmt | 平台 | 平台 | 平台 | 平台 | 平台 |
| 网络用户接收 | 提供者 | 提供者 | 提供者 | 提供者 | 不支持 |
| 网点规范化 | 增强 | 增强 | 增强 | 增强 | 不支持 |
| 交付 跟踪 | 提供者 | 提供者 | 提供者 | 提供者 | 不支持 |
| 正在输入电子邮件 | 增强 | 增强 | 增强 | 增强 | 不支持 |
| 订阅Mgmt | 增强 | 增强 | 平台 | 平台 | 平台 |
| 压制 | 提供者 | 提供者 | 提供者 | 提供者 | 平台 |
| 未订阅 UrlGeneration | 平台 | 平台 | 平台 | 平台 | 平台 |
| 预定发送 | 提供者 | 提供者 | 平台 | 平台 | 平台 |
| 打开点击跟踪 | 提供者 | 提供者 | 供应商* | 不支持 | 不支持 |
| 自动跟踪 | 提供者 | 不支持 | 不支持 | 不支持 | 不支持 |
| 电子邮件连接 | 平台 | 平台 | 平台 | 平台 | 平台 |
| 电子邮件页眉Mgmt | 平台 | 平台 | 平台 | 平台 | 平台 |
| 附录 | 提供者 | 提供者 | 提供者 | 提供者 | 提供者 |
| 高级随附处理 | 平台 | 平台 | 平台 | 平台 | 平台 |
| dkimSpf 数据 | 提供者 | 提供者 | 提供者 | 提供者 | 不支持 |
| 链接显示 | 提供者 | 提供者 | 不支持 | 不支持 | 不支持 |
| 复试 | 平台 | 平台 | 平台 | 平台 | 平台 |
| 多服务失败 | 平台 | 平台 | 平台 | 平台 | 平台 |
* 邮政标记支持每个消息的开放和链接跟踪; TrackOpens: false 在服务器级别上打开跟踪时被忽略.
特定提供者的显著限制:
- 发送Grid
scheduledSend: 72小时最大排程窗口 - 邮件枪
scheduledSend: 3天最大排程窗口 - 用户
webhooksReceive编号 :deliveryTracking: 需要 SNS 专题配置
运行配置
能力感知路由是选入. 添加一个 routing 区域到您的配置 :
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:路由器完全跳过提供者,按优先级顺序尝试下一个. 如果没有提供者支持该特性, aFeatureUnsupportedError被抛出.- 退化伐木: 由
degradation.logLevel(单位:千美元)'silent'|'info'|'warn'|'error') (中文(简体) ). 何时includeDocLinks实值true,日志信息包括与降解文件的链接.
Redis 解析器设置
默认情况下,能力矩阵会从内映快照中解决. 对于跨多个实例的共享或动态能力数据,使用Redis后置的解析器:
# Set the environment variable to enable Redis resolver auto-detection
export EMAIL_MANAGER_REDIS_URL="redis://localhost:6379"
工厂createCapabilityResolver)自动检测环境变量并创建一个 SafeCapabilityResolver 将Redis解析器包裹在记忆回落中 若为 ioredis 没有安装或 Redis 无法使用, 它会悄悄地回到内膜解析器.
Redis 解析器选项
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)
});
您也可以提供自己的解析器执行:
const config: EmailManagerConfig = {
providers: [/* ... */],
routing: {
strategy: 'primary-failover',
capabilityResolver: myCustomResolver, // Must implement CapabilityResolver interface
},
};
回复中的搜索元数据
当路由活动时, SendResult 包含a routing 字段 :
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 接口 :
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/电子邮件发送器 - 核心电子邮件发送功能
- @ bernierllc/ template- 引擎 - 模板渲染引擎
- @bernierllc/魔法链接 - 安全代币生成