@builder6/email 3.2.3 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +407 -15
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,29 +1,421 @@
|
|
|
1
1
|
# Builder6 Email Module
|
|
2
2
|
|
|
3
|
+
Builder6 Email 模块为 Builder6 平台提供完整的邮件发送和队列管理功能,支持 SMTP 邮件发送、邮件队列处理、批量发送等企业级邮件服务。
|
|
3
4
|
|
|
4
|
-
##
|
|
5
|
+
## 功能特性
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
- **SMTP 邮件发送**: 支持标准 SMTP 协议发送邮件
|
|
8
|
+
- **邮件队列**: 基于数据库的邮件队列,支持失败重试
|
|
9
|
+
- **批量发送**: 支持批量邮件发送,可配置批次大小
|
|
10
|
+
- **定时发送**: 自动定时检查队列并发送待发邮件
|
|
11
|
+
- **邮件模板**: 支持 HTML 和文本邮件模板
|
|
12
|
+
- **附件支持**: 支持邮件附件发送
|
|
13
|
+
- **邮件验证**: 自动验证邮件地址格式
|
|
14
|
+
- **发送日志**: 记录邮件发送状态和日志
|
|
15
|
+
- **失败处理**: 发送失败自动重试机制
|
|
16
|
+
- **队列保留**: 可选择发送后保留或删除队列记录
|
|
17
|
+
|
|
18
|
+
## 安装
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @builder6/email
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
或
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
yarn add @builder6/email
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 环境变量
|
|
31
|
+
|
|
32
|
+
### SMTP 服务器配置
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# 启用邮件服务
|
|
36
|
+
B6_EMAIL_ENABLED=true
|
|
37
|
+
|
|
38
|
+
# 发件人地址
|
|
7
39
|
B6_EMAIL_FROM=Steedos <noreply@steedos.com>
|
|
8
|
-
|
|
40
|
+
|
|
41
|
+
# SMTP 服务器地址
|
|
42
|
+
B6_EMAIL_HOST=email.example.amazonaws.com
|
|
43
|
+
|
|
44
|
+
# SMTP 服务器端口
|
|
9
45
|
B6_EMAIL_PORT=465
|
|
10
|
-
|
|
11
|
-
|
|
46
|
+
|
|
47
|
+
# SMTP 用户名
|
|
48
|
+
B6_EMAIL_USERNAME=your-smtp-username
|
|
49
|
+
|
|
50
|
+
# SMTP 密码
|
|
51
|
+
B6_EMAIL_PASSWORD=your-smtp-password
|
|
52
|
+
|
|
53
|
+
# 使用 SSL/TLS
|
|
54
|
+
B6_EMAIL_SECURE=true
|
|
55
|
+
|
|
56
|
+
# 启用调试模式
|
|
57
|
+
B6_EMAIL_DEBUG=false
|
|
58
|
+
|
|
59
|
+
# 启用日志记录
|
|
60
|
+
B6_EMAIL_LOGGER=true
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 邮件队列配置
|
|
64
|
+
|
|
65
|
+
当 `B6_EMAIL_ENABLED=true` 时,系统会启动定时任务从 `_mail_queue` 集合中读取邮件并发送。
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# 邮件队列检查间隔(毫秒),默认 3000ms = 3秒
|
|
69
|
+
STEEDOS_EMAIL_QUEUE_INTERVAL=3000
|
|
70
|
+
|
|
71
|
+
# 每次批量发送的邮件数量,默认 1
|
|
72
|
+
STEEDOS_EMAIL_QUEUE_BATCH_SIZE=10
|
|
73
|
+
|
|
74
|
+
# 邮件发送超时时间(毫秒),默认 60000ms = 60秒
|
|
75
|
+
STEEDOS_EMAIL_QUEUE_TIMEOUT=60000
|
|
76
|
+
|
|
77
|
+
# 邮件发送后是否保留队列记录,默认 false(删除)
|
|
78
|
+
STEEDOS_EMAIL_QUEUE_KEEPS=false
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 常用 SMTP 提供商配置
|
|
82
|
+
|
|
83
|
+
#### Gmail
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
B6_EMAIL_HOST=smtp.gmail.com
|
|
87
|
+
B6_EMAIL_PORT=465
|
|
88
|
+
B6_EMAIL_SECURE=true
|
|
89
|
+
B6_EMAIL_USERNAME=your-email@gmail.com
|
|
90
|
+
B6_EMAIL_PASSWORD=your-app-password
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### Amazon SES
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
B6_EMAIL_HOST=email-smtp.us-east-1.amazonaws.com
|
|
97
|
+
B6_EMAIL_PORT=465
|
|
98
|
+
B6_EMAIL_SECURE=true
|
|
99
|
+
B6_EMAIL_USERNAME=your-smtp-username
|
|
100
|
+
B6_EMAIL_PASSWORD=your-smtp-password
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### Outlook/Office 365
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
B6_EMAIL_HOST=smtp.office365.com
|
|
107
|
+
B6_EMAIL_PORT=587
|
|
12
108
|
B6_EMAIL_SECURE=false
|
|
109
|
+
B6_EMAIL_USERNAME=your-email@outlook.com
|
|
110
|
+
B6_EMAIL_PASSWORD=your-password
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
#### 腾讯企业邮箱
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
B6_EMAIL_HOST=smtp.exmail.qq.com
|
|
117
|
+
B6_EMAIL_PORT=465
|
|
118
|
+
B6_EMAIL_SECURE=true
|
|
119
|
+
B6_EMAIL_USERNAME=your-email@company.com
|
|
120
|
+
B6_EMAIL_PASSWORD=your-password
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## 使用示例
|
|
124
|
+
|
|
125
|
+
### 在 NestJS 应用中集成
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { Module } from '@nestjs/common';
|
|
129
|
+
import { EmailModule } from '@builder6/email';
|
|
130
|
+
|
|
131
|
+
@Module({
|
|
132
|
+
imports: [EmailModule],
|
|
133
|
+
})
|
|
134
|
+
export class AppModule {}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 使用 EmailService 发送邮件
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { EmailService } from '@builder6/email';
|
|
141
|
+
|
|
142
|
+
constructor(private emailService: EmailService) {}
|
|
143
|
+
|
|
144
|
+
// 发送简单文本邮件
|
|
145
|
+
async sendTextEmail() {
|
|
146
|
+
await this.emailService.send({
|
|
147
|
+
to: 'user@example.com',
|
|
148
|
+
subject: 'Welcome to Builder6',
|
|
149
|
+
text: 'Thank you for joining us!'
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 发送 HTML 邮件
|
|
154
|
+
async sendHtmlEmail() {
|
|
155
|
+
await this.emailService.send({
|
|
156
|
+
to: 'user@example.com',
|
|
157
|
+
subject: 'Welcome to Builder6',
|
|
158
|
+
html: '<h1>Welcome!</h1><p>Thank you for joining us!</p>'
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// 发送带附件的邮件
|
|
163
|
+
async sendEmailWithAttachment() {
|
|
164
|
+
await this.emailService.send({
|
|
165
|
+
to: 'user@example.com',
|
|
166
|
+
subject: 'Document Attached',
|
|
167
|
+
html: '<p>Please find the document attached.</p>',
|
|
168
|
+
attachments: [
|
|
169
|
+
{
|
|
170
|
+
filename: 'document.pdf',
|
|
171
|
+
path: '/path/to/document.pdf'
|
|
172
|
+
}
|
|
173
|
+
]
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// 发送给多个收件人
|
|
178
|
+
async sendToMultipleRecipients() {
|
|
179
|
+
await this.emailService.send({
|
|
180
|
+
to: ['user1@example.com', 'user2@example.com'],
|
|
181
|
+
cc: ['manager@example.com'],
|
|
182
|
+
bcc: ['admin@example.com'],
|
|
183
|
+
subject: 'Team Update',
|
|
184
|
+
html: '<p>Important team update...</p>'
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### 使用邮件队列
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
import { EmailQueueService } from '@builder6/email';
|
|
193
|
+
|
|
194
|
+
constructor(private emailQueueService: EmailQueueService) {}
|
|
195
|
+
|
|
196
|
+
// 添加邮件到队列
|
|
197
|
+
async queueEmail() {
|
|
198
|
+
await this.emailQueueService.addToQueue({
|
|
199
|
+
to: 'user@example.com',
|
|
200
|
+
subject: 'Queued Email',
|
|
201
|
+
html: '<p>This email will be sent by the queue processor.</p>',
|
|
202
|
+
priority: 1, // 优先级,数字越小优先级越高
|
|
203
|
+
scheduledAt: new Date('2024-01-20 10:00:00') // 计划发送时间
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// 批量添加邮件到队列
|
|
208
|
+
async queueBatchEmails(users: User[]) {
|
|
209
|
+
const emails = users.map(user => ({
|
|
210
|
+
to: user.email,
|
|
211
|
+
subject: 'Newsletter',
|
|
212
|
+
html: `<p>Hello ${user.name},</p><p>Your monthly newsletter...</p>`
|
|
213
|
+
}));
|
|
214
|
+
|
|
215
|
+
await this.emailQueueService.addBatchToQueue(emails);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// 获取队列状态
|
|
219
|
+
async getQueueStatus() {
|
|
220
|
+
const pending = await this.emailQueueService.getPendingCount();
|
|
221
|
+
const failed = await this.emailQueueService.getFailedCount();
|
|
222
|
+
|
|
223
|
+
return { pending, failed };
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// 重试失败的邮件
|
|
227
|
+
async retryFailedEmails() {
|
|
228
|
+
await this.emailQueueService.retryFailed();
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## 邮件队列数据结构
|
|
233
|
+
|
|
234
|
+
邮件队列存储在 MongoDB 的 `_mail_queue` 集合中:
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
interface MailQueue {
|
|
238
|
+
_id: string;
|
|
239
|
+
to: string | string[];
|
|
240
|
+
cc?: string | string[];
|
|
241
|
+
bcc?: string | string[];
|
|
242
|
+
from?: string;
|
|
243
|
+
subject: string;
|
|
244
|
+
text?: string;
|
|
245
|
+
html?: string;
|
|
246
|
+
attachments?: Array<{
|
|
247
|
+
filename: string;
|
|
248
|
+
path?: string;
|
|
249
|
+
content?: Buffer;
|
|
250
|
+
}>;
|
|
251
|
+
status: 'pending' | 'sending' | 'sent' | 'failed';
|
|
252
|
+
priority: number; // 1-10,数字越小优先级越高
|
|
253
|
+
attempts: number; // 发送尝试次数
|
|
254
|
+
lastAttempt?: Date;
|
|
255
|
+
scheduledAt?: Date; // 计划发送时间
|
|
256
|
+
sentAt?: Date;
|
|
257
|
+
error?: string;
|
|
258
|
+
created: Date;
|
|
259
|
+
modified: Date;
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## 邮件模板
|
|
264
|
+
|
|
265
|
+
### 使用 LiquidJS 模板
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
import { EmailService } from '@builder6/email';
|
|
269
|
+
|
|
270
|
+
async sendTemplatedEmail(user: User) {
|
|
271
|
+
const template = `
|
|
272
|
+
<h1>Welcome, {{ user.name }}!</h1>
|
|
273
|
+
<p>Your account has been created successfully.</p>
|
|
274
|
+
<p>Username: {{ user.username }}</p>
|
|
275
|
+
<p>Email: {{ user.email }}</p>
|
|
276
|
+
`;
|
|
277
|
+
|
|
278
|
+
const html = this.emailService.renderTemplate(template, { user });
|
|
279
|
+
|
|
280
|
+
await this.emailService.send({
|
|
281
|
+
to: user.email,
|
|
282
|
+
subject: 'Welcome to Builder6',
|
|
283
|
+
html
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## API 端点
|
|
289
|
+
|
|
290
|
+
模块提供以下主要 API 端点(如果启用 HTTP 接口):
|
|
291
|
+
|
|
292
|
+
- **POST `/api/v6/email/send`**: 直接发送邮件(需要管理员权限)
|
|
293
|
+
- **POST `/api/v6/email/queue`**: 添加邮件到队列
|
|
294
|
+
- **GET `/api/v6/email/queue/status`**: 获取队列状态
|
|
295
|
+
- **POST `/api/v6/email/queue/retry`**: 重试失败的邮件
|
|
296
|
+
|
|
297
|
+
## 邮件队列处理流程
|
|
298
|
+
|
|
299
|
+
1. **添加到队列**: 邮件信息写入 `_mail_queue` 集合,状态为 `pending`
|
|
300
|
+
2. **定时检查**: 每隔 `STEEDOS_EMAIL_QUEUE_INTERVAL` 毫秒检查一次队列
|
|
301
|
+
3. **批量处理**: 按优先级和创建时间排序,每次处理 `STEEDOS_EMAIL_QUEUE_BATCH_SIZE` 条
|
|
302
|
+
4. **发送邮件**: 更新状态为 `sending`,调用 SMTP 发送
|
|
303
|
+
5. **更新状态**:
|
|
304
|
+
- 成功:更新为 `sent`,记录发送时间
|
|
305
|
+
- 失败:更新为 `failed`,记录错误信息,增加尝试次数
|
|
306
|
+
6. **清理队列**: 如果 `STEEDOS_EMAIL_QUEUE_KEEPS=false`,删除已发送的邮件
|
|
307
|
+
|
|
308
|
+
## 失败重试策略
|
|
309
|
+
|
|
310
|
+
- 默认最大重试次数:3 次
|
|
311
|
+
- 重试间隔:指数退避(exponential backoff)
|
|
312
|
+
- 第 1 次失败:等待 1 分钟
|
|
313
|
+
- 第 2 次失败:等待 5 分钟
|
|
314
|
+
- 第 3 次失败:等待 15 分钟
|
|
315
|
+
- 超过最大重试次数后,邮件保持 `failed` 状态,需要手动处理
|
|
316
|
+
|
|
317
|
+
## 性能优化
|
|
318
|
+
|
|
319
|
+
### 批量发送优化
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
# 增加批量大小以提高吞吐量
|
|
323
|
+
STEEDOS_EMAIL_QUEUE_BATCH_SIZE=50
|
|
324
|
+
|
|
325
|
+
# 减少检查间隔以更快处理队列
|
|
326
|
+
STEEDOS_EMAIL_QUEUE_INTERVAL=1000
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### 连接池优化
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
# 配置 SMTP 连接池
|
|
333
|
+
B6_EMAIL_POOL=true
|
|
334
|
+
B6_EMAIL_POOL_MAX_CONNECTIONS=10
|
|
335
|
+
B6_EMAIL_POOL_MAX_MESSAGES=100
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## 监控和日志
|
|
339
|
+
|
|
340
|
+
### 启用详细日志
|
|
341
|
+
|
|
342
|
+
```bash
|
|
13
343
|
B6_EMAIL_DEBUG=true
|
|
14
344
|
B6_EMAIL_LOGGER=true
|
|
15
|
-
B6_EMAIL_ENABLED=true
|
|
16
345
|
```
|
|
17
346
|
|
|
18
|
-
|
|
347
|
+
### 日志信息包括
|
|
348
|
+
|
|
349
|
+
- SMTP 连接状态
|
|
350
|
+
- 邮件发送详情
|
|
351
|
+
- 错误和异常信息
|
|
352
|
+
- 队列处理统计
|
|
353
|
+
|
|
354
|
+
## 使用场景
|
|
355
|
+
|
|
356
|
+
- **用户通知**: 注册欢迎邮件、密码重置、系统通知
|
|
357
|
+
- **营销邮件**: 新闻通讯、产品更新、促销活动
|
|
358
|
+
- **交易邮件**: 订单确认、发货通知、发票
|
|
359
|
+
- **报告邮件**: 定期生成并发送统计报告
|
|
360
|
+
- **警报邮件**: 系统异常、安全警告、监控告警
|
|
361
|
+
- **工作流通知**: 审批通知、任务提醒、到期提醒
|
|
362
|
+
|
|
363
|
+
## 安全注意事项
|
|
364
|
+
|
|
365
|
+
1. **凭据保护**: 使用环境变量存储 SMTP 凭据,不要硬编码
|
|
366
|
+
2. **邮件验证**: 验证收件人邮箱地址格式,防止发送到无效地址
|
|
367
|
+
3. **速率限制**: 遵守 SMTP 提供商的发送速率限制
|
|
368
|
+
4. **SPF/DKIM**: 配置 SPF 和 DKIM 记录提高邮件送达率
|
|
369
|
+
5. **退订链接**: 营销邮件应包含退订链接
|
|
370
|
+
6. **敏感信息**: 避免在邮件中传输敏感信息,使用加密链接
|
|
371
|
+
|
|
372
|
+
## 依赖项
|
|
373
|
+
|
|
374
|
+
### 主要依赖
|
|
375
|
+
|
|
376
|
+
- `nodemailer`: ^7.0.11 - 邮件发送库
|
|
377
|
+
- `email-addresses`: ^5.0.0 - 邮件地址解析和验证
|
|
378
|
+
- `bluebird`: ^3.7.2 - Promise 增强库
|
|
379
|
+
- `lodash`: ^4.17.21 - 工具函数库
|
|
380
|
+
|
|
381
|
+
### Peer Dependencies
|
|
382
|
+
|
|
383
|
+
- `@builder6/core`: ^3.0.10 - 核心功能模块
|
|
384
|
+
- `@builder6/moleculer`: ^3.0.10 - 微服务框架
|
|
385
|
+
- `@nestjs/common`: ^11.0.0 - NestJS 核心
|
|
386
|
+
- `@nestjs/core`: ^11.0.0 - NestJS 核心
|
|
387
|
+
- `@nestjs/swagger`: ^11.0.7 - API 文档
|
|
388
|
+
|
|
389
|
+
## 开发
|
|
390
|
+
|
|
391
|
+
### 构建
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
npm run build
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### 监听模式
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
npm run build:watch
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### 格式化代码
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
npm run format
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
## 故障排查
|
|
410
|
+
|
|
411
|
+
### 常见问题
|
|
19
412
|
|
|
20
|
-
|
|
413
|
+
1. **邮件发送失败**: 检查 SMTP 配置和网络连接
|
|
414
|
+
2. **认证失败**: 验证用户名和密码是否正确
|
|
415
|
+
3. **被拒绝发送**: 检查是否超过了发送限制
|
|
416
|
+
4. **邮件进入垃圾箱**: 配置 SPF、DKIM 和 DMARC 记录
|
|
417
|
+
5. **队列积压**: 增加批量大小或减少检查间隔
|
|
21
418
|
|
|
22
|
-
|
|
419
|
+
## License
|
|
23
420
|
|
|
24
|
-
|
|
25
|
-
STEEDOS_EMAIL_QUEUE_INTERVAL=3000 # 邮件定时器,单位:毫秒, 默认值:3000
|
|
26
|
-
STEEDOS_EMAIL_QUEUE_BATCH_SIZE=1 # 邮件队列批量发送数量,默认值:1
|
|
27
|
-
STEEDOS_EMAIL_QUEUE_TIMEOUT=60000 # 邮件队列超时时间,单位:毫秒,默认值:60000
|
|
28
|
-
STEEDOS_EMAIL_QUEUE_KEEPS=false # 邮件发送之后是否保留邮件队列,默认值:false
|
|
29
|
-
```
|
|
421
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@builder6/email",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"nodemailer": "^7.0.11"
|
|
19
19
|
},
|
|
20
20
|
"peerDependencies": {
|
|
21
|
-
"@builder6/core": "^
|
|
22
|
-
"@builder6/moleculer": "^
|
|
21
|
+
"@builder6/core": "^4.0.0",
|
|
22
|
+
"@builder6/moleculer": "^4.0.0",
|
|
23
23
|
"@nestjs/common": "^11.0.0",
|
|
24
24
|
"@nestjs/core": "^11.0.0",
|
|
25
25
|
"@nestjs/swagger": "^11.0.7"
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"publishConfig": {
|
|
28
28
|
"access": "public"
|
|
29
29
|
},
|
|
30
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "6d6e13fed8d4b3c6de14f84dcb6287c5661ea6f6",
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/bluebird": "^3.5.42"
|
|
33
33
|
}
|