如何为Nodemailer的SMTPTransport挂载日志器?自定义Winston日志器无错误日志
我来帮你排查这个头疼的问题——自定义Winston日志器挂到SMTPTransport后完全不记录错误,结合你给出的代码片段,咱们一步步拆解可能的原因和解决办法:
1. 先确认Winston日志器本身能正常工作
这是最基础的排查步骤:先脱离Nodemailer,单独测试你的Winston实例能不能输出错误日志。比如在代码里加一行:
customLogger.error('测试错误日志');
如果这行都没有输出,那问题根本不在Nodemailer集成上,而是你的Winston配置有问题:
- 检查transports是否正确配置(比如文件传输的路径是否有权限,控制台传输是否启用)
- 确认日志级别(level)设置是否包含
error,如果设成了info或更高,error日志会被过滤 - 检查format是否正确,有没有把日志内容格式化到能被你看到的地方
2. 正确给SMTPTransport挂载自定义Winston日志器
从你代码里的this.logger = shared.getLogger(...)来看,你可能还在使用Nodemailer内置的日志工具,而不是直接传入自定义Winston实例。正确的做法是在初始化SMTPTransport时,直接把Winston实例传给options的logger字段:
const winston = require('winston'); // 先创建你的自定义Winston日志器 const customLogger = winston.createLogger({ level: 'error', format: winston.format.json(), transports: [ new winston.transports.File({ filename: 'error.log', level: 'error' }), new winston.transports.Console() ] }); // 初始化SMTPTransport时传入自定义logger const transporter = nodemailer.createTransport({ host: 'your-smtp-host', port: 587, auth: { user: 'your-email', pass: 'your-password' }, // 关键:直接传Winston实例 logger: customLogger, // 可选:给日志加组件标识,方便区分 component: 'smtp-transport' });
3. 确保错误回调里显式调用日志方法
Nodemailer的内置logger会自动处理错误日志,但自定义logger不会自动帮你做这件事。你需要在send方法的错误回调里,手动调用Winston的error方法:
send(mail, callback) { // ...你的其他代码 connection.send(envelope, mail.message.createReadStream(), (err, info) => { if (err) { // 手动记录错误日志,带上上下文信息(比如信封、错误详情) this.logger.error('SMTP邮件发送失败', { error: err.stack || err.message, envelope: envelope, timestamp: new Date().toISOString() }); // 别忘了把错误传给回调 return callback(err); } // 可选:记录成功日志 this.logger.info('SMTP邮件发送成功', { messageId: info.messageId }); callback(null, info); }); }
4. 监听SMTPTransport的全局错误事件
SMTPTransport继承了EventEmitter,有些底层错误可能不会在send回调里抛出,而是通过error事件触发。所以要额外监听这个事件,避免遗漏日志:
transporter.on('error', (err) => { customLogger.error('SMTPTransport全局错误', { error: err.stack || err.message, timestamp: new Date().toISOString() }); });
最后再检查一个细节:Nodemailer的logLevel设置
如果你同时设置了logLevel选项,要确保它的级别低于或等于Winston的级别。比如Winston设为error,Nodemailer的logLevel就不能设为info(否则错误日志会被Nodemailer过滤掉)。不过用自定义logger时,logLevel通常会被忽略,但保险起见可以检查一下。
内容的提问来源于stack exchange,提问作者Ulysses

