@bernierllc/email-sender

中文文档
5.14.0发布于 2026/11/05MITTypeScriptCommonJS近 30 天下载 2498

有提供者- 不可知界面和 SendGrid 高级功能的电子邮件发送( 模板、 经核实的发送者、 速率限制)

中文使用文档
文档目录38 节
  1. 特征
  2. 安装
  3. 快速启动
  4. 基本用途
  5. 发送Grid 配置
  6. AWS SES 配置
  7. 邮件枪配置
  8. 邮戳配置
  9. API 参考
  10. 电子邮件发送器
  11. 类型
  12. 提供者的能力
  13. 电子邮件提供能力接口
  14. 能力输入
  15. 提供能力摘要
  16. 宣布自定义提供者的能力
  17. Zod 验证
  18. 显示电子邮件安全
  19. 以白名单粘贴( Block 非白名单)
  20. 用重写粘接( 重定向到测试电子邮件)
  21. 制作(所有电子邮件)
  22. 发送前检查收件人安全性
  23. 基于环境的动态配置
  24. 实例
  25. 以附件发送电子邮件
  26. 用自定义信头发送电子邮件
  27. 带有不同内容的批次电子邮件
  28. 处理错误
  29. 提供者支助
  30. 目前得到支持
  31. 添加新供应商
  32. 测试
  33. 捐款
  34. 一体化状况
  35. 重大退化
  36. 许可证
  37. 支助
  38. 信息分析参数

@bernierllc/电子邮件发送器

用提供者-不可知界面发送基本电子邮件的核心工具 .

特征

  • 提供者-不可知论: 支持多个电子邮件提供者( SMTP, SendGrid, SES, Mailgun, Postmark)
  • 显示电子邮件安全: 防止非生产环境中的意外电子邮件发送
  • 类型脚本: 完整类型脚本支持并严格打字
  • 验证: 全面的电子邮件和配置验证
  • 附录: 文件附件的支持
  • 批量发送: 高效发送多封电子邮件
  • 处理错误: 有力的错误处理和报告
  • 测试: 全面试验覆盖率

安装

npm install @bernierllc/email-sender

说明: 此软件包使用对等依赖性 。 您必须分别安装 :

# For SMTP provider
npm install nodemailer

# For AWS SES provider
npm install aws-sdk

快速启动

基本用途

import { EmailSender } from '@bernierllc/email-sender';

// Configure SMTP provider
const config = {
  provider: 'smtp' as const,
  host: 'smtp.gmail.com',
  port: 587,
  secure: false,
  username: '[email protected]',
  password: 'your-app-password',
  fromEmail: '[email protected]',
  fromName: 'Your App',
};

// Create email sender
const emailSender = new EmailSender(config);

// Send an email
const result = await emailSender.sendEmail({
  toEmail: '[email protected]',
  toName: 'John Doe',
  subject: 'Welcome to our app!',
  htmlContent: '<h1>Welcome!</h1><p>Thank you for joining us.</p>',
  textContent: 'Welcome! Thank you for joining us.',
});

if (result.success) {
  console.log('Email sent successfully:', result.messageId);
} else {
  console.error('Failed to send email:', result.errorMessage);
}

发送Grid 配置

import { EmailSender } from '@bernierllc/email-sender';

const config = {
  provider: 'sendgrid' as const,
  apiKey: 'your-sendgrid-api-key',
  fromEmail: '[email protected]',
  fromName: 'Your App',
  // Optional: point every SendGrid call (mail send, templates, senders) at
  // another host, e.g. a local mock in tests. Give the bare origin; a
  // trailing `/v3` is also accepted. Defaults to https://api.sendgrid.com.
  endpoint: process.env.SENDGRID_API_BASE_URL,
};

const emailSender = new EmailSender(config);

AWS SES 配置

import { EmailSender } from '@bernierllc/email-sender';

const config = {
  provider: 'ses' as const,
  apiKey: 'your-aws-access-key',
  secretKey: 'your-aws-secret-key',
  region: 'us-east-1',
  fromEmail: '[email protected]',
  fromName: 'Your App',
  sandbox: false, // Set to true if in SES sandbox mode
};

const emailSender = new EmailSender(config);

邮件枪配置

import { EmailSender } from '@bernierllc/email-sender';

const config = {
  provider: 'mailgun' as const,
  apiKey: 'your-mailgun-api-key',
  domain: 'yourdomain.com',
  region: 'us', // or 'eu' for European region
  fromEmail: '[email protected]',
  fromName: 'Your App',
};

const emailSender = new EmailSender(config);

邮戳配置

import { EmailSender } from '@bernierllc/email-sender';

const config = {
  provider: 'postmark' as const,
  apiKey: 'your-postmark-api-key',
  accountToken: 'your-postmark-account-token', // Optional, for template operations
  fromEmail: '[email protected]',
  fromName: 'Your App',
};

const emailSender = new EmailSender(config);

API 参考

电子邮件发送器

发送邮件的主课.

构造器

new EmailSender(config: EmailProviderConfig)

方法

sendEmail(email: EmailMessage): Promise<SendResult>

发送一个电子邮件.

const result = await emailSender.sendEmail({
  toEmail: '[email protected]',
  subject: 'Test Email',
  htmlContent: '<h1>Hello</h1>',
});
sendBatch(emails: EmailMessage[]): Promise<SendResult[]>

分批发送多封邮件 .

const results = await emailSender.sendBatch([
  { toEmail: '[email protected]', subject: 'Email 1', htmlContent: '<h1>Email 1</h1>' },
  { toEmail: '[email protected]', subject: 'Email 2', htmlContent: '<h1>Email 2</h1>' },
]);
validateConfiguration(): EmailValidationResult

验证提供者配置 .

const validation = emailSender.validateConfiguration();
if (!validation.isValid) {
  console.error('Configuration errors:', validation.errors);
}
validateEmailMessage(email: EmailMessage): EmailValidationResult

发送前验证电子邮件信息 .

const validation = emailSender.validateEmailMessage(email);
if (!validation.isValid) {
  console.error('Email validation errors:', validation.errors);
}
testConnection(): Promise<boolean>

测试连接到电子邮件提供者 .

const isConnected = await emailSender.testConnection();
if (isConnected) {
  console.log('Connection successful');
} else {
  console.error('Connection failed');
}
getCapabilities(): EmailProviderCapabilities

获取当前提供者的能力.

const capabilities = emailSender.getCapabilities();
console.log('Supports attachments:', capabilities.supportsAttachments);
console.log('Max batch size:', capabilities.maxBatchSize);

类型

电子邮件信

interface EmailMessage {
  toEmail: string;
  toName?: string;
  fromEmail?: string;
  fromName?: string;
  subject: string;
  htmlContent?: string;
  textContent?: string;
  replyTo?: string;
  headers?: Record<string, string>;
  attachments?: EmailAttachment[];
  metadata?: Record<string, any>;
  /** Per-message open, click and UTM tracking; omitted = the provider account's default. */
  tracking?: { opens?: boolean; clicks?: boolean; utm?: boolean };
}

tracking: { clicks: false } 在下面的提供者上保留无法重写HTML和文本部分的链接,这是一次性链接(签名、邀请、密码重置)所需要的。 它映射到 SendGrid tracking_settings邮件枪 o:tracking-clicks编号 :o:tracking-opens邮戳 TrackLinks编号 :TrackOpens (邮戳忽略 opens: false 在服务器一级打开跟踪)和Mandrill track_clicks编号 :track_opens;不跟踪的提供者忽略了它. SMTP2GO设定只跟踪每个API密钥,并忽略了该覆盖,所以使用一个按下跟踪键进行一次性链接.

tracking: { utm: false } 停止将分析查询参数(UTM标签)附加到链接中;使其未定义账户默认值。 它不停止点击跟踪: 链接只按逐字记录 { clicks: false, utm: false }。 。 。 . utm: true 强制标记使用账户的 UTM 值 。 只有SendGrid尊重它(tracking_settings.ganalytics每个供养者都忽视它 getCapabilities().features.utmTracking 说是哪个.

电子邮件连接

interface EmailAttachment {
  filename: string;
  content: string; // Base64 encoded
  contentType?: string;
  disposition?: 'attachment' | 'inline';
}

发送结果

interface SendResult {
  success: boolean;
  messageId?: string;
  errorMessage?: string;
  providerResponse?: any;
  metadata?: Record<string, any>;
}

电子邮件 ProviderConfig

interface EmailProviderConfig {
  provider: 'sendgrid' | 'ses' | 'mailgun' | 'postmark' | 'smtp';
  apiKey?: string;
  region?: string;
  endpoint?: string;
  fromEmail: string;
  fromName?: string;
  replyTo?: string;
  webhookUrl?: string;
  webhookSecret?: string;
  sandbox?: boolean;
  // SMTP specific options
  host?: string;
  port?: number;
  secure?: boolean;
  username?: string;
  password?: string;
}

提供者的能力

每个供应商通过下列途径暴露其能力: getCapabilities() 方法。 能力接口既包括遗留布尔旗,也包括扩大的旗帜 features 用于精细能力检查的地图.

电子邮件提供能力接口

interface EmailProviderCapabilities {
  // Legacy boolean flags (always available)
  supportsBatch: boolean;
  supportsTemplates: boolean;
  supportsWebhooks: boolean;
  supportsAttachments: boolean;
  supportsCustomHeaders: boolean;
  supportsDeliveryTracking: boolean;
  maxBatchSize: number;
  maxAttachmentSize: number;

  // Expanded feature map (optional, populated by capability-aware providers)
  features?: Record<string, CapabilityEntry>;
}

能力输入

表格中的每个条目 features 映射描述特定特性是如何被支持的 :

type CapabilitySource = 'provider' | 'platform' | 'enhanced' | 'unsupported';

interface CapabilityEntry {
  source: CapabilitySource;      // How the feature is implemented
  description: string;           // Human-readable description
  limitations?: string;          // Known limitations (e.g., "72hr max scheduling window")
  degradation?: {                // Present when platform polyfill has a degradation strategy
    strategy: string;
    description: string;
    docUrl: string;
  } | null;
  overridable: boolean;          // Whether the entry can be overridden at runtime
}

提供能力摘要

提供者批次模板网络呼号附录自定义信头交货跟踪
发送Grid有(个性化)是(动态模板)是 (Event Webhook) (英语)对对对
邮件枪是(接收变量)是(存储模板)对对对对
邮戳是(批发API)是(服务器侧)对对对对
用户是 (发送Blk电子邮件)是(电子邮件模板)是(通过SNS)是( raw 电子邮件)对是(通过SNS)
SMTP 软件顺序*没有服务器侧没有是(微小中型企业)对没有

*SMTP批发由平台相继处理,而不是由供应商自行处理.

宣布自定义提供者的能力

执行自定义提供者时,通过返回适当的值来声明能力 getCapabilities()数字 :

import { EmailProvider, EmailProviderCapabilities, CapabilityEntry } from '@bernierllc/email-sender';

class CustomProvider extends EmailProvider {
  getCapabilities(): EmailProviderCapabilities {
    return {
      supportsBatch: true,
      supportsTemplates: false,
      supportsWebhooks: true,
      supportsAttachments: true,
      supportsCustomHeaders: true,
      supportsDeliveryTracking: true,
      maxBatchSize: 500,
      maxAttachmentSize: 10 * 1024 * 1024, // 10 MB

      // Optional: declare fine-grained features for capability-aware routing
      features: {
        sendEmail: {
          source: 'provider',
          description: 'Send email via custom API',
          degradation: null,
          overridable: false,
        },
        batchSend: {
          source: 'provider',
          description: 'Batch send via custom API bulk endpoint',
          degradation: null,
          overridable: true,
        },
        scheduledSend: {
          source: 'unsupported',
          description: 'Custom provider does not support scheduled send',
          degradation: null,
          overridable: false,
        },
      },
    };
  }
}

当 features 地图已存在 @bernierllc/email-manager 能力路由器将其用于智能供应商选择. 缺席时,路由器会倒回静态能力矩阵.

Zod 验证

两者 CapabilityEntry 财务报告和审定财务报表 DegradationInfo 拥有运行时间验证的 Zod 计划 :

import { capabilityEntrySchema, degradationInfoSchema } from '@bernierllc/email-sender';

const result = capabilityEntrySchema.safeParse(entry);
if (!result.success) {
  console.error('Invalid capability entry:', result.error.issues);
}

显示电子邮件安全

使用中转安全功能,防止在非生产环境中发送意外邮件.

以白名单粘贴( Block 非白名单)

import { EmailSender } from '@bernierllc/email-sender';

const emailSender = new EmailSender({
  provider: 'smtp' as const,
  host: 'smtp.example.com',
  port: 587,
  username: 'user',
  password: 'pass',
  fromEmail: '[email protected]',
  stagingSafety: {
    enabled: true,
    environment: 'staging',
    whitelist: ['[email protected]', '[email protected]', '[email protected]'],
    blockNonWhitelisted: true,
    logBlocked: true,
  },
});

// This will send (whitelisted)
await emailSender.sendEmail({
  toEmail: '[email protected]',
  subject: 'Test Email',
  htmlContent: '<p>This email will be sent</p>',
});

// This will be blocked (not whitelisted)
const result = await emailSender.sendEmail({
  toEmail: '[email protected]',
  subject: 'Test Email',
  htmlContent: '<p>This email will be blocked</p>',
});
console.log(result.success); // false
console.log(result.errorMessage); // "Email blocked by safety manager: ..."

用重写粘接( 重定向到测试电子邮件)

const emailSender = new EmailSender({
  provider: 'smtp' as const,
  host: 'smtp.example.com',
  port: 587,
  username: 'user',
  password: 'pass',
  fromEmail: '[email protected]',
  stagingSafety: {
    enabled: true,
    environment: 'staging',
    whitelist: ['[email protected]'], // Admin emails go through normally
    rewriteTo: '[email protected]', // All other emails redirected here
    blockNonWhitelisted: false,
    logBlocked: true,
  },
});

// This will be sent to [email protected] instead
await emailSender.sendEmail({
  toEmail: '[email protected]',
  subject: 'Test Email',
  htmlContent: '<p>This will be sent to [email protected]</p>',
});

制作(所有电子邮件)

const emailSender = new EmailSender({
  provider: 'smtp' as const,
  host: 'smtp.example.com',
  port: 587,
  username: 'user',
  password: 'pass',
  fromEmail: '[email protected]',
  stagingSafety: {
    enabled: true,
    environment: 'production',
    whitelist: [], // Not used in production
    blockNonWhitelisted: false,
    logBlocked: false,
  },
});

// All emails are allowed in production
await emailSender.sendEmail({
  toEmail: '[email protected]',
  subject: 'Production Email',
  htmlContent: '<p>This email will be sent</p>',
});

发送前检查收件人安全性

const safetyResult = emailSender.checkRecipientSafety('[email protected]');
console.log('Safety check result:', safetyResult);

if (safetyResult && !safetyResult.allowed) {
  console.log('Email would be blocked:', safetyResult.reason);
}

基于环境的动态配置

const environment = process.env.NODE_ENV || 'development';

const emailSender = new EmailSender({
  provider: 'smtp' as const,
  host: 'smtp.example.com',
  port: 587,
  username: 'user',
  password: 'pass',
  fromEmail: '[email protected]',
  stagingSafety: {
    enabled: environment !== 'production',
    environment: environment as 'development' | 'staging' | 'production',
    whitelist: environment === 'staging'
      ? ['[email protected]', '[email protected]']
      : [],
    rewriteTo: environment === 'development' ? '[email protected]' : undefined,
    blockNonWhitelisted: environment === 'staging',
    logBlocked: true,
  },
});

console.log('Current environment:', environment);
console.log('Safety enabled:', emailSender.isSafetyEnabled());
console.log('Safety config:', emailSender.getSafetyConfig());

实例

以附件发送电子邮件

import { EmailSender } from '@bernierllc/email-sender';
import fs from 'fs';

const emailSender = new EmailSender(config);

const attachment = {
  filename: 'report.pdf',
  content: fs.readFileSync('report.pdf').toString('base64'),
  contentType: 'application/pdf',
  disposition: 'attachment' as const,
};

const result = await emailSender.sendEmail({
  toEmail: '[email protected]',
  subject: 'Monthly Report',
  htmlContent: '<h1>Monthly Report</h1><p>Please find the attached report.</p>',
  attachments: [attachment],
});

用自定义信头发送电子邮件

const result = await emailSender.sendEmail({
  toEmail: '[email protected]',
  subject: 'Priority Message',
  htmlContent: '<h1>Important Update</h1>',
  headers: {
    'X-Priority': '1',
    'X-Custom-Header': 'custom-value',
  },
});

带有不同内容的批次电子邮件

const emails = [
  {
    toEmail: '[email protected]',
    toName: 'User One',
    subject: 'Personalized Email 1',
    htmlContent: '<h1>Hello User One!</h1>',
  },
  {
    toEmail: '[email protected]',
    toName: 'User Two',
    subject: 'Personalized Email 2',
    htmlContent: '<h1>Hello User Two!</h1>',
  },
];

const results = await emailSender.sendBatch(emails);

处理错误

try {
  const result = await emailSender.sendEmail(email);
  
  if (result.success) {
    console.log('Email sent successfully');
  } else {
    console.error('Email failed:', result.errorMessage);
    
    // Check if it's a validation error
    const validation = emailSender.validateEmailMessage(email);
    if (!validation.isValid) {
      console.error('Validation errors:', validation.errors);
    }
  }
} catch (error) {
  console.error('Unexpected error:', error);
}

提供者支助

目前得到支持

  • SMTP 软件: 用节点符完全支持
  • 发送Grid: 完全支持 SendGrid API
  • 警报器: 用 AWS SDK 提供完全支持( 需要) aws-sdk 依赖同伴)
  • 邮件枪: 完全支持 Mailgun API
  • 邮戳: 完全支持 Postmark API

添加新供应商

要添加一个新的提供者,请扩展 EmailProvider 基准类 :

import { EmailProvider, EmailMessage, SendResult } from '@bernierllc/email-sender';

export class CustomProvider extends EmailProvider {
  async sendEmail(email: EmailMessage): Promise<SendResult> {
    // Implement your provider logic here
  }
  
  async sendBatch(emails: EmailMessage[]): Promise<SendResult[]> {
    // Implement batch sending logic
  }
  
  async getDeliveryStatus(messageId: string): Promise<DeliveryStatus | null> {
    // Implement delivery status checking
  }
  
  async processWebhook(payload: any, signature: string): Promise<WebhookEvent[]> {
    // Implement webhook processing
  }
}

测试

运行测试套件 :

npm test

进行覆盖测试 :

npm run test:coverage

捐款

  1. 叉子存储器
  2. 创建特性分支
  3. 做你的改变
  4. 添加新功能测试
  5. 确保所有测试通过
  6. 提交拉动请求

一体化状况

  • 伐木机集成:不适用 - Email-sender是一个低等的用途,不需要@bernierllc/logger集成. 消费者申请应视需要处理伐木问题.
  • 多克套装: 准备 - 完整的类型Doc/JSDoc文档。 基于 Markdown 的 README 有广泛的示例 .
  • NeverHub 整合:不适用 -- -- 电子邮件发送器是一个无国籍的功能,侧重于电子邮件发送。 @bernierllc/ 绝不需要适应器.

重大退化

这个软件包的设计是为了在配置的电子邮件提供者之外,在没有外部依赖的情况下独立工作. 所有功能都是自成一体的,有明显的错误处理和验证.

许可证

ISC 许可证 - 详情见LICENSE文件.

支助

请在GitHub上打开一个问题或联系Bernier LLC.

信息分析参数

SendGrid 通过现有的跟踪对象支持清晰的每个消息的 UTM 值 :

tracking: {
  utm: true,
  utmParameters: {
    source: 'newsletter', medium: 'email', campaign: 'launch',
    term: '', content: 'hero',
  },
}

参数仅以 utm: true。 。 。 . utm: false 只发送 ganalytics.enable: false; 省略 utm 保留账户行为。 Oinducted/null 参数字段将账户值留在控制中;空字符串是准确传输的. 除字符串/ null 抛出之外启用的参数值 EmailValidationError 在HTTP之前。 库不发明提供者长度限制. 提供商: utmTracking 能力是不支持的,忽略这些参数.

点击和开放跟踪仍然可独立配置。 有效载荷合同并不保证某一提供商对空值或有点击跟踪功能的分析进行送出-链接处理;在作为应用行为提供这些组合之前,对照用于交付的账户对这些组合进行验证.

版本与发布记录

@bernierllc/email-sender 共发布 22 个版本,首次发布于 2025/07/29;过去 12 个月发布了 17 个版本。

版本发布日期距今
5.14.0latest2026/11/053 天前
5.13.02026/10/2415 天前
5.12.02026/10/2316 天前
5.11.02026/10/1920 天前
5.10.02026/10/021 个月前
5.9.02026/09/301 个月前

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

@bernierllc/email-sender 是什么?

有提供者- 不可知界面和 SendGrid 高级功能的电子邮件发送( 模板、 经核实的发送者、 速率限制)

如何安装 @bernierllc/email-sender?

在项目目录运行 npm install @bernierllc/email-sender,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:aws-sdk(^2.1000.0)、nodemailer(^6.9.0)、@sendgrid/mail(^8.1.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@bernierllc/email-sender 支持 TypeScript 吗?

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

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

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

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

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

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

@bernierllc/email-sender 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

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

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

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

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