@flun/mailer 2.1.24 → 2.1.25

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.
@@ -34,16 +34,16 @@ class SmtpPool extends EventEmitter {
34
34
  }
35
35
 
36
36
  /**
37
- * 将电子邮件加入队列,使用选定设置发送
37
+ * 将电子邮件加入队列,使用选定设置发送
38
38
  *
39
39
  * @param {Object} mail 邮件对象
40
40
  * @param {Function} callback 回调函数
41
41
  */
42
42
  send(mail, callback) {
43
- if (this._closed) return false; // 如果连接池已关闭,则返回false
43
+ if (this._closed) return false; // 如果连接池已关闭,则返回false
44
44
  this._queue.push({ mail, requeueAttempts: 0, callback }); // 将邮件加入队列(包括重试尝试计数)
45
45
 
46
- // 如果队列长度达到最大连接数且处于空闲状态,则标记为非空闲
46
+ // 如果队列长度达到最大连接数且处于空闲状态,则标记为非空闲
47
47
  if (this.idling && this._queue.length >= this.options.maxConnections) this.idling = false;
48
48
  setImmediate(() => this.#processMessages()); // 立即开始处理消息
49
49
 
@@ -51,13 +51,13 @@ class SmtpPool extends EventEmitter {
51
51
  }
52
52
 
53
53
  /**
54
- * 关闭池中的所有连接。如果有消息正在发送,则稍后关闭连接
54
+ * 关闭池中的所有连接;如果有消息正在发送,则稍后关闭连接
55
55
  */
56
56
  close() {
57
- this._closed = true, clearTimeout(this._rateLimit.timeout); // 标记为已关闭并清除速率限制定时器(如果存在)
57
+ this._closed = true, clearTimeout(this._rateLimit.timeout); // 标记为已关闭并清除速率限制定时器(如果存在)
58
58
  const conLen = this._connections.length;
59
59
  let queLen = this._queue.length;
60
- if (!conLen && !queLen) return; // 如果没有连接和队列,则直接返回
60
+ if (!conLen && !queLen) return; // 如果没有连接和队列,则直接返回
61
61
 
62
62
  // 移除所有可用连接
63
63
  for (let i = conLen - 1; i >= 0; i--) {
@@ -75,7 +75,7 @@ class SmtpPool extends EventEmitter {
75
75
  const entry = this._queue.shift();
76
76
  if (entry && typeof entry.callback === 'function') {
77
77
  try {
78
- entry.callback(new Error(`连接池已关闭,队列中还有 ${queLen} 个待处理请求`));
78
+ entry.callback(new Error(`连接池已关闭,队列中还有 ${queLen} 个待处理请求`));
79
79
  } catch (E) {
80
80
  this.logger.error({ err: E, tnx: 'callback' }, '回调错误: %s', E.message);
81
81
  }
@@ -88,7 +88,7 @@ class SmtpPool extends EventEmitter {
88
88
  }
89
89
 
90
90
  /**
91
- * 检查队列和可用连接。如果有要发送的消息且有可用连接,则使用此连接发送邮件
91
+ * 检查队列和可用连接;如果有要发送的消息且有可用连接,则使用此连接发送邮件
92
92
  */
93
93
  #processMessages() {
94
94
  let connection;
@@ -97,8 +97,8 @@ class SmtpPool extends EventEmitter {
97
97
  this.idling = true, this.emit('idle'); // 标记为空闲
98
98
  };
99
99
 
100
- if (this._closed) return; // 如果已关闭,则不执行任何操作
101
- // 如果队列为空,则不执行任何操作
100
+ if (this._closed) return; // 如果已关闭,则不执行任何操作
101
+ // 如果队列为空,则不执行任何操作
102
102
  if (!queLen) {
103
103
  if (!this.idling) idlingEmit();
104
104
  return;
@@ -111,10 +111,10 @@ class SmtpPool extends EventEmitter {
111
111
  break;
112
112
  }
113
113
 
114
- // 如果没有可用连接且未达到最大连接数,则创建新连接
114
+ // 如果没有可用连接且未达到最大连接数,则创建新连接
115
115
  const { maxConnections } = this.options;
116
116
  if (!connection && conLen < maxConnections) connection = this.#createConnection();
117
- if (!connection) return this.idling = false; // 如果没有可用连接,则标记为非空闲并返回
117
+ if (!connection) return this.idling = false; // 如果没有可用连接,则标记为非空闲并返回
118
118
  if (!this.idling && queLen < maxConnections) idlingEmit(); // 检查处理队列中是否有空闲空间
119
119
 
120
120
  // 从队列中取出一个条目并分配给连接
@@ -155,12 +155,13 @@ class SmtpPool extends EventEmitter {
155
155
  // 监听池资源事件
156
156
  connection.on('available', () => {
157
157
  this.logger.debug({ tnx: 'connection', cid, action: 'available' }, '连接 #%s 变为可用', cid);
158
- this._closed ? this.close() : this.#processMessages(); // 如果已关闭,则从连接列表中移除此连接,否则检查是否还有其它发送
158
+ // 如果已关闭,则从连接列表中移除此连接,否则检查是否还有其它发送
159
+ this._closed ? this.close() : this.#processMessages();
159
160
  }).once('error', err => {
160
161
  if (err.code !== 'EMAXLIMIT') this.logger.error({ err, tnx: 'pool', cid }, '池错误 #%s: %s', cid, err.message);
161
162
  else this.logger.debug({ tnx: 'pool', cid, action: 'maxlimit' }, '连接 #%s 已达到最大消息限制', cid);
162
163
 
163
- // 如果连接有队列条目,则调用回调并传递错误
164
+ // 如果连接有队列条目,则调用回调并传递错误
164
165
  if (connection.queueEntry) {
165
166
  try {
166
167
  connection.queueEntry.callback(err);
@@ -176,11 +177,12 @@ class SmtpPool extends EventEmitter {
176
177
  this.#removeConnection(connection);
177
178
  const { queueEntry } = connection;
178
179
  if (queueEntry)
179
- // 如果连接在发送时关闭,将消息重新加入队列;如果未达到最大重试次数,则重新排队
180
+ // 如果连接在发送时关闭,将消息重新加入队列;如果未达到最大重试次数,则重新排队
180
181
  setTimeout(() => {
181
- this.#shouldRequeueOnClose(queueEntry) ? this.#requeueOnClose(connection) : this.#failOnClose(connection);
182
+ this.#shouldRequeueOnClose(queueEntry) ? this.#requeueOnClose(connection)
183
+ : this.#failOnClose(connection);
182
184
  this.#continueProcessing();
183
- }, 50); // 必须等待一下,因为"error"处理程序的回调可能在下一个事件循环中调用
185
+ }, 50); // 必须等待一下,因为"error"处理程序的回调可能在下一个事件循环中调用
184
186
  else {
185
187
  if (!this._closed && this.idling && !this._connections.length) this.emit('clear');
186
188
  this.#continueProcessing();
@@ -209,7 +211,8 @@ class SmtpPool extends EventEmitter {
209
211
  queueEntry.callback(new Error('连接关闭后达到最大重试次数'));
210
212
  } catch (E) {
211
213
  this.logger.error(
212
- { err: E, tnx: 'callback', messageId: queueEntry.messageId, cid: id }, '回调错误 #%s: %s', id, E.message);
214
+ { err: E, tnx: 'callback', messageId: queueEntry.messageId, cid: id },
215
+ '回调错误 #%s: %s', id, E.message);
213
216
  }
214
217
  connection.queueEntry = false;
215
218
  }
@@ -223,12 +226,12 @@ class SmtpPool extends EventEmitter {
223
226
  queueEntry.requeueAttempts++;
224
227
  const { messageId, requeueAttempts } = queueEntry;
225
228
  this.logger.debug({ tnx: 'pool', cid: id, messageId, action: 'requeue' },
226
- '为 #%s 重新排队消息 <%s>。尝试次数: #%s', messageId, id, requeueAttempts);
229
+ '为 #%s 重新排队消息 <%s>;尝试次数: #%s', messageId, id, requeueAttempts);
227
230
  this._queue.unshift(queueEntry), connection.queueEntry = false;
228
231
  }
229
232
 
230
233
  /**
231
- * 如果池未关闭,则继续处理消息
234
+ * 如果池未关闭,则继续处理消息
232
235
  */
233
236
  #continueProcessing() {
234
237
  this._closed ? this.close() : setTimeout(() => this.#processMessages(), 100);
@@ -245,7 +248,7 @@ class SmtpPool extends EventEmitter {
245
248
  }
246
249
 
247
250
  /**
248
- * 检查连接是否达到当前速率限制,如果是,则将可用性回调加入队列
251
+ * 检查连接是否达到当前速率限制,如果是,则将可用性回调加入队列
249
252
  *
250
253
  * @param {Function} callback 速率限制清除后运行的回调函数
251
254
  */
@@ -274,7 +277,7 @@ class SmtpPool extends EventEmitter {
274
277
  }
275
278
 
276
279
  /**
277
- * 如果队列中有空闲插槽,则返回true
280
+ * 如果队列中有空闲插槽,则返回true
278
281
  */
279
282
  isIdle() {
280
283
  return this.idling;
@@ -16,7 +16,7 @@ class PoolResource extends EventEmitter {
16
16
  constructor(pool) {
17
17
  super();
18
18
  this.pool = pool, this.options = pool.options, this.logger = this.pool.logger; // 所属连接池,连接选项,日志记录器
19
- if (this.options.auth) this.auth = this.getAuth({}); // 如果提供了认证信息,则设置认证
19
+ if (this.options.auth) this.auth = this.getAuth({}); // 如果提供了认证信息,则设置认证
20
20
 
21
21
  this._connection = false, this._connected = false; // SMTP连接实例,连接状态标志
22
22
  this.messages = 0, this.available = true; // 已发送消息计数,资源可用性标志
@@ -17,7 +17,7 @@ class SmtpTransport extends EventEmitter {
17
17
  super();
18
18
  this.name = 'SMTP';
19
19
  initSmtpConstructor(this, options, SmtpConnection, 'smtpTransport'); // 初始化SMTP连接
20
- if (this.options.auth) this.auth = this.getAuth({}); // 如果提供了认证信息,则设置认证
20
+ if (this.options.auth) this.auth = this.getAuth({}); // 如果提供了认证信息,则设置认证
21
21
  }
22
22
 
23
23
  /**
@@ -45,7 +45,8 @@ class SmtpTransport extends EventEmitter {
45
45
  state = { returned: false }, cleanC = setupConnectionHandlers(state, connection, callback, this),
46
46
  // 发送消息
47
47
  sendMessage = () => {
48
- const { envelope, readStream, from, to, messageId } = prepareMessageForSending(mail, this.logger);//邮件预处理
48
+ //邮件预处理
49
+ const { envelope, readStream, from, to, messageId } = prepareMessageForSending(mail, this.logger);
49
50
  connection.send(envelope, readStream, (err, info) => {
50
51
  state.returned = true, connection.close();
51
52
 
@@ -7,15 +7,15 @@ import { PK, getLogger, prepareMessageForSending, resolveStream } from './shared
7
7
  * >查看定义:@see {@link StreamTransport}
8
8
  * @param {Object} [options] 配置选项
9
9
  * @param {boolean} [options.buffer=false]
10
- * - `false`(默认):**异步流式返回**,邮件内容以可读流 (Readable Stream) 的形式给出。
11
- * 适合:需要实时推送、管道转发,或邮件体积很大不想一次全装进内存时。
12
- * - `true`:**先收完整再返回**,邮件内容会被拼成一个 Buffer 对象一次性给你。
13
- * 适合:需要加密、签名、保存文件等必须先拿到完整内容的场景。
10
+ * - `false`(默认):**异步流式返回**,邮件内容以可读流 (Readable Stream) 的形式给出;
11
+ * 适合:需要实时推送、管道转发,或邮件体积很大不想一次全装进内存时;
12
+ * - `true`:**先收完整再返回**,邮件内容会被拼成一个 Buffer 对象一次性给你;
13
+ * 适合:需要加密、签名、保存文件等必须先拿到完整内容的场景;
14
14
  * @param {string} [options.newline='']
15
- * 生成的邮件正文使用哪种换行符:
15
+ * 生成的邮件正文使用哪种换行符:
16
16
  * - `'windows'`, `'win'`, `'dos'` 或 `'\r\n'` → 使用 Windows 风格换行 `\r\n`
17
17
  * - `'unix'`、空字符串或其他值 → 使用 Unix 风格换行 `\n`
18
- * 通常保持默认即可;只有当你明确知道邮件客户端在 Windows 上有换行问题时才需设置。
18
+ * 通常保持默认即可;只有当你明确知道邮件客户端在 Windows 上有换行问题时才需设置;
19
19
  *
20
20
  * @constructor
21
21
  */
@@ -25,7 +25,8 @@ class StreamTransport {
25
25
 
26
26
  const { component = 'streamTransport', newline = '' } = this.options;
27
27
  this.logger = getLogger(this.options, { component }); // 初始化日志记录器
28
- this.winbreak = ['win', 'windows', 'dos', '\r\n'].includes(newline.toString().toLowerCase()); // 根据配置确定换行符类型
28
+ // 根据配置确定换行符类型
29
+ this.winbreak = ['win', 'windows', 'dos', '\r\n'].includes(newline.toString().toLowerCase());
29
30
  }
30
31
 
31
32
  /**
@@ -44,14 +45,15 @@ class StreamTransport {
44
45
  this.logger.error({ err, tnx: 'send', messageId }, context, messageId, err.message), done(err);
45
46
  };
46
47
 
47
- // 如果不使用缓冲区,直接返回流(流可读时才认为成功)
48
+ // 如果不使用缓冲区,直接返回流(流可读时才认为成功)
48
49
  if (!this.options.buffer) {
49
50
  readStream.once('readable', () => done(null, { envelope, messageId, message: readStream }))
50
- .once('error', err => handleError(err, '为 %s 创建消息流失败。%s'))
51
+ .once('error', err => handleError(err, '为 %s 创建消息流失败;%s'))
51
52
  }
52
53
 
53
54
  // 将流数据读取到Buffer中
54
- resolveStream(readStream, (err, value) => err ? handleError(err) : done(null, { envelope, messageId, message: value }));
55
+ resolveStream(readStream,
56
+ (err, value) => err ? handleError(err) : done(null, { envelope, messageId, message: value }));
55
57
  });
56
58
  }
57
59
  }
@@ -5,7 +5,7 @@ const normalized = {}, // 储存规范的服务对象
5
5
 
6
6
  /**
7
7
  * 规范化键名
8
- * 移除非字母数字、点号和连字符的字符,并转换为小写
8
+ * 移除非字母数字、点号和连字符的字符,并转换为小写
9
9
  * @param {String} key - 需要规范化的键名
10
10
  * @returns {String} 规范化后的键名
11
11
  */
@@ -16,7 +16,7 @@ const normalized = {}, // 储存规范的服务对象
16
16
 
17
17
  /**
18
18
  * 规范化服务对象
19
- * 过滤掉不需要的字段(domains 和 aliases)
19
+ * 过滤掉不需要的字段(domains 和 aliases)
20
20
  * @param {Object} service - 原始服务对象
21
21
  * @returns {Object} 规范化后的服务对象
22
22
  */
@@ -36,12 +36,13 @@ Object.keys(SERVICES).forEach(key => {
36
36
  normalized[normalizeKey(sourceKey)] = normalizeService(service);
37
37
  };
38
38
  // 处理主键,别名,域名
39
- addServiceEntry(key), (service.aliases ?? []).forEach(addServiceEntry), (service.domains ?? []).forEach(addServiceEntry);
39
+ addServiceEntry(key),
40
+ (service.aliases ?? []).forEach(addServiceEntry), (service.domains ?? []).forEach(addServiceEntry);
40
41
  });
41
42
 
42
43
  /**
43
44
  * 根据提供的键名解析 SMTP 配置;
44
- * 键名可以是服务名称(如 'Gmail')、别名(如 'Google Mail')或邮箱地址(如 'test@googlemail.com')
45
+ * 键名可以是服务名称(如 'Gmail')、别名(如 'Google Mail')或邮箱地址(如 'test@googlemail.com')
45
46
  * >查看定义:@see {@link wellKnown}
46
47
  * @param {String} key - 服务名称、别名或邮箱地址
47
48
  * @returns {Object|Boolean} SMTP 配置对象,如果未找到则返回 false
package/lib/xoauth2.js CHANGED
@@ -8,13 +8,13 @@ import { nmfetch, getLogger, resolveStream } from './shared.js';
8
8
  * 有关获取用户所需 refreshToken 的离线访问,请参阅离线访问
9
9
  * https://developers.google.com/accounts/docs/OAuth2WebServer#offline
10
10
  *
11
- * 使用 provisionCallback 自定义方法生成访问令牌的用法:
11
+ * 使用 provisionCallback 自定义方法生成访问令牌的用法:
12
12
  * provisionCallback(user, renew, callback);
13
13
  * * user 是要获取令牌的用户名
14
- * * renew 是一个布尔值,如果为 true 表示现有令牌失败需要更新
14
+ * * renew 是一个布尔值,如果为 true 表示现有令牌失败需要更新
15
15
  * * callback 是带有 (error, accessToken [, expires]) 的回调函数
16
16
  * * accessToken 是一个字符串
17
- * * expires 是可选的过期时间(毫秒)
17
+ * * expires 是可选的过期时间(毫秒)
18
18
  * 如果使用了 provisionCallback,则 @flun/mailer 不会尝试自行生成令牌
19
19
  * >查看定义:@see {@link XOAuth2}
20
20
  * @constructor
@@ -26,8 +26,8 @@ import { nmfetch, getLogger, resolveStream } from './shared.js';
26
26
  * @param {String} options.accessUrl 令牌生成端点,默认为 'https://accounts.google.com/o/oauth2/token'
27
27
  * @param {String} options.accessToken 现有的有效访问令牌
28
28
  * @param {String} options.privateKey JWT 私钥
29
- * @param {Number} options.expires 可选的访问令牌过期时间(毫秒)
30
- * @param {Number} options.timeout 可选的访问令牌 TTL(秒)
29
+ * @param {Number} options.expires 可选的访问令牌过期时间(毫秒)
30
+ * @param {Number} options.timeout 可选的访问令牌 TTL(秒)
31
31
  * @param {Function} options.provisionCallback 需要新访问令牌时运行的函数
32
32
  */
33
33
  class XOAuth2 extends Stream {
@@ -39,7 +39,8 @@ class XOAuth2 extends Stream {
39
39
  expires, timeout, accessUrl, customHeaders = {}, customParams = {} } = this.options;
40
40
  // 服务账户验证
41
41
  if (this.options?.serviceClient) {
42
- if (!privateKey || !user) return setImmediate(() => this.emit('error', new Error('服务账户需要 "privateKey" 和 "user" 选项!')));
42
+ if (!privateKey || !user)
43
+ return setImmediate(() => this.emit('error', new Error('服务账户需要 "privateKey" 和 "user" 选项!')));
43
44
  this.options.serviceRequestTimeout = Math.min(Math.max(Number(serviceRequestTimeout) || 0, 0), 3600) || 5 * 60;
44
45
  }
45
46
 
@@ -55,35 +56,37 @@ class XOAuth2 extends Stream {
55
56
  }
56
57
 
57
58
  /**
58
- * 返回或生成(如果之前的已过期)XOAuth2 令牌
59
+ * 返回或生成(如果之前的已过期)XOAuth2 令牌
59
60
  *
60
- * @param {Boolean} renew 如果为 false 则使用缓存的访问令牌(如果可用)
61
+ * @param {Boolean} renew 如果为 false 则使用缓存的访问令牌(如果可用)
61
62
  * @param {Function} callback 带有错误对象和令牌字符串的回调函数
62
63
  */
63
64
  getToken(renew, callback) {
64
- const { user, refreshToken, serviceClient } = this.options, { accessToken, expires, provisionCallback, renewing } = this,
65
+ const { user, refreshToken, serviceClient } = this.options,
66
+ { accessToken, expires, provisionCallback, renewing } = this,
65
67
  // 重用令牌
66
68
  reuseToken = message => {
67
69
  this.logger.debug({ tnx: 'OAUTH2', user, action: 'reuse' }, message, user);
68
70
  return callback(null, accessToken);
69
71
  };
70
72
 
71
- // 如果不需要续订且令牌有效,则直接重用
73
+ // 如果不需要续订且令牌有效,则直接重用
72
74
  if (!renew && accessToken && (!expires || expires > Date.now())) return reuseToken('为 %s 重用现有访问令牌');
73
- // 检查是否可以续订,如果不能,返回当前令牌或错误
75
+ // 检查是否可以续订,如果不能,返回当前令牌或错误
74
76
  if (!provisionCallback && !refreshToken && !serviceClient) {
75
- if (accessToken) return reuseToken('为 %s 重用现有访问令牌(无刷新能力)');
76
- this.logger.error({ tnx: 'OAUTH2', user, action: 'renew' }, '无法为 %s 续订访问令牌:无可用刷新机制', user);
77
+ if (accessToken) return reuseToken('为 %s 重用现有访问令牌(无刷新能力)');
78
+ this.logger.error({ tnx: 'OAUTH2', user, action: 'renew' }, '无法为 %s 续订访问令牌:无可用刷新机制', user);
77
79
  return callback(new Error("无法为用户创建新的访问令牌"));
78
80
  }
79
81
 
80
- // 如果已经在续订中,将此请求加入队列而不是开始另一个
82
+ // 如果已经在续订中,将此请求加入队列而不是开始另一个
81
83
  if (renewing) return this.renewalQueue.push({ renew, callback });
82
84
  this.renewing = true;
83
85
 
84
86
  // 处理令牌续订完成 - 处理队列中的请求并清理
85
87
  const generateCallback = (err, accessToken) => {
86
- this.renewalQueue.forEach(item => item.callback(err, accessToken)), this.renewalQueue = [], this.renewing = false;
88
+ this.renewalQueue.forEach(item => item.callback(err, accessToken)),
89
+ this.renewalQueue = [], this.renewing = false;
87
90
 
88
91
  if (err) this.logger.error({ err, tnx: 'OAUTH2', user, action: 'renew' }, '为 %s 生成新访问令牌失败', user);
89
92
  else this.logger.info({ tnx: 'OAUTH2', user, action: 'renew' }, '为 %s 生成新访问令牌', user);
@@ -102,9 +105,9 @@ class XOAuth2 extends Stream {
102
105
  * 更新令牌值
103
106
  *
104
107
  * @param {String} accessToken 新的访问令牌
105
- * @param {Number} timeout 访问令牌生命周期(秒)
108
+ * @param {Number} timeout 访问令牌生命周期(秒)
106
109
  *
107
- * 触发 'token' 事件:{ user: 用户电子邮件地址, accessToken: 新的访问令牌, timeout: TTL(秒)}
110
+ * 触发 'token' 事件:{ user: 用户电子邮件地址, accessToken: 新的访问令牌, timeout: TTL(秒)}
108
111
  */
109
112
  updateToken(accessToken = '', timeout) {
110
113
  this.accessToken = accessToken, timeout = Math.max(Number(timeout) || 0, 0);
@@ -124,7 +127,8 @@ class XOAuth2 extends Stream {
124
127
  if (serviceClient) {
125
128
  // 服务账户 - https://developers.google.com/identity/protocols/OAuth2ServiceAccount
126
129
  const iat = Math.floor(Date.now() / 1000), // unix 时间
127
- tokenData = { iss: serviceClient, scope, sub: user, aud: accessUrl, iat, exp: iat + serviceRequestTimeout };
130
+ tokenData = { iss: serviceClient, scope, sub: user, aud: accessUrl, iat,
131
+ exp: iat + serviceRequestTimeout };
128
132
  let assertion;
129
133
  try {
130
134
  assertion = this.jwtSignRS256(tokenData);
@@ -165,7 +169,7 @@ class XOAuth2 extends Stream {
165
169
  return callback(new Error('无效的身份验证响应'));
166
170
  }
167
171
 
168
- // 记录响应数据(隐藏访问令牌的完整内容)
172
+ // 记录响应数据(隐藏访问令牌的完整内容)
169
173
  const logData = Object.fromEntries(
170
174
  Object.entries(data).map(([k, v = '']) => [k, k === 'access_token' ? `${v.toString().slice(0, 6)}...` : v])
171
175
  );
@@ -173,7 +177,7 @@ class XOAuth2 extends Stream {
173
177
  this.logger.debug({ tnx, user, action }, '响应: %s', JSON.stringify(logData));
174
178
 
175
179
  if (data.error) {
176
- let errorMessage = data.error; // 错误响应:https://tools.ietf.org/html/rfc6749#section-5.2
180
+ let errorMessage = data.error; // 错误响应:https://tools.ietf.org/html/rfc6749#section-5.2
177
181
 
178
182
  if (data.error_description) errorMessage += `: ${data.error_description}`;
179
183
  if (data.error_uri) errorMessage += ` (${data.error_uri})`;
@@ -202,19 +206,20 @@ class XOAuth2 extends Stream {
202
206
  }
203
207
 
204
208
  /**
205
- * 自定义 POST 请求处理程序。
209
+ * 自定义 POST 请求处理程序;
206
210
  * 这仅在需要保持 Windows 中路径短时才需要;通常此模块
207
- * 是依赖项的依赖项,如果它尝试 require 某些东西
208
- * 比如 request 模块,路径对 Windows 来说会变得太长而无法处理。
209
- * 由于只进行简单的 POST 请求,所以实际上不需要复杂的
210
- * 逻辑支持(没有重定向,没有其他任何东西)。
211
+ * 是依赖项的依赖项,如果它尝试 require 某些东西
212
+ * 比如 request 模块,路径对 Windows 来说会变得太长而无法处理;
213
+ * 由于只进行简单的 POST 请求,所以实际上不需要复杂的
214
+ * 逻辑支持(没有重定向,没有其他任何东西);
211
215
  *
212
216
  * @param {String} url 要 POST 的 URL
213
217
  * @param {String|Buffer} payload 要 POST 的有效负载
214
218
  * @param {Function} callback 带有 (err, buff) 的回调函数
215
219
  */
216
220
  postRequest(url, payload, params, callback) {
217
- const req = nmfetch(url, { method: 'post', headers: params.customHeaders, body: payload, allowErrorResponse: true });
221
+ const req = nmfetch(url, { method: 'post', headers: params.customHeaders, body: payload,
222
+ allowErrorResponse: true });
218
223
  resolveStream(req, callback); // 将流数据读取到Buffer中
219
224
  }
220
225
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@flun/mailer",
3
- "version": "2.1.24",
4
- "description": "A powerful and flexible email sending library for Node.js with multiple transport support (SMTP, SMTP Pool, Sendmail, Stream, JSON, SES)",
3
+ "version": "2.1.25",
4
+ "description": "Node.js 邮件发送库;支持 SMTP、SMTP Pool、Sendmail、Stream、JSON、SES 多种传输;",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": "./index.js"
@@ -53,10 +53,10 @@
53
53
  "npm": ">=10.0.0"
54
54
  },
55
55
  "dependencies": {
56
- "@aws-sdk/client-sesv2": "^3.1146.0"
56
+ "@aws-sdk/client-sesv2": "^3.1156.0"
57
57
  },
58
58
  "devDependencies": {
59
- "eslint": "^10.11.0",
59
+ "eslint": "^10.13.0",
60
60
  "jest": "^30.5.2"
61
61
  },
62
62
  "peerDependencies": {