Node.js IMAP邮件监听函数执行后出现ECONNREFUSED错误排查
问题分析与修复方案
错误根源
结合你的代码与控制台输出,核心问题如下:
- 多余嵌套Promise破坏代码结构:
waitForEmail主Promise内部的嵌套Promise完全无意义,你试图用return阻止后续代码,但该return仅作用于内部Promise的回调函数,无法终止主Promise内的逻辑执行,还导致语法不完整。 - 异步sleep未做await处理:调用
sleep(5,6)时未添加await,导致resolve(emailInfo)在sleep完成前就执行,虽不直接引发连接错误,但会造成逻辑时序混乱。 - 连接关闭后的错误未被妥善过滤:调用
imap.end()后,IMAP实例仍可能触发残留的连接事件,你的错误处理逻辑在已完成resolve/reject的情况下仍会打印错误,造成混淆。
控制台错误信息
Listening for new messages... New message has been delivered! Number of new messages: 1 { "sender": "wbxtfa@mymail.vip", "subject": "Mailbox Verification Code", "body": "The PIN for email@hotmail.com is: sWmO-604273 (expired on 26/03 17:43)" } CHUJ IMAP error after connection closed: AggregateError at internalConnectMultiple (node:net:1114:18) at afterConnectMultiple (node:net:1667:5) { code: 'ECONNREFUSED', source: 'socket', [errors]: [ Error: connect ECONNREFUSED ::1:143 at createConnectionError (node:net:1634:14) at afterConnectMultiple (node:net:1664:40) { errno: -4078, code: 'ECONNREFUSED', syscall: 'connect', address: '::1', port: 143 }, Error: connect ECONNREFUSED 127.0.0.1:143 at createConnectionError (node:net:1634:14) at afterConnectMultiple (node:net:1664:40) { errno: -4078, code: 'ECONNREFUSED', syscall: 'connect', address: '127.0.0.1', port: 143 } ] } IMAP connection ended
修复后的完整代码
const Imap = require('imap'); const { simpleParser } = require('mailparser'); // 监听新邮件的异步函数 async function waitForEmail(imapConfig, timeout = 100000) { return new Promise((resolve, reject) => { const imap = new Imap(imapConfig); let isResolvedOrRejected = false; // 防止多次resolve/reject的标志位 function openInbox(cb) { imap.openBox('INBOX', false, cb); } imap.once('error', function (err) { if (!isResolvedOrRejected) { console.error('IMAP连接错误:', err); isResolvedOrRejected = true; reject(err); } else { // 已完成处理,忽略后续非关键错误 console.log('IMAP连接关闭后出现的非关键错误:', err); } }); imap.once('end', function () { console.log('IMAP连接已终止'); if (!isResolvedOrRejected) { isResolvedOrRejected = true; reject(new Error('IMAP连接意外关闭')); } }); imap.connect(); imap.once('ready', function () { openInbox(function (err, box) { if (err) { console.error('打开收件箱失败:', err); if (!isResolvedOrRejected) { isResolvedOrRejected = true; reject(err); } imap.end(); return; } console.log('正在监听新邮件...'); // 监听新邮件到达事件,收到后立即移除监听避免重复触发 const onMail = async function (numNewMsgs) { console.log(`收到新邮件!新邮件数量: ${numNewMsgs}`); imap.removeListener('mail', onMail); const fetch = imap.seq.fetch(box.messages.total + ':*', { bodies: '', struct: true }); fetch.on('message', function (msg) { let emailBuffer = []; msg.on('body', function (stream) { stream.on('data', function (chunk) { emailBuffer.push(chunk); }); }); msg.once('end', async function () { try { const mail = await simpleParser(Buffer.concat(emailBuffer)); const emailInfo = { sender: mail.from.value.map(a => a.address).join(', '), subject: mail.subject, body: mail.text || mail.html || '无文本内容' }; console.log(JSON.stringify(emailInfo, null, 2)); // 关闭IMAP连接 imap.end(); // 若需要延迟,这里添加await保证时序 await sleep(5, 6); if (!isResolvedOrRejected) { isResolvedOrRejected = true; console.log('处理完成') resolve(emailInfo); } } catch (parseErr) { console.error('解析邮件失败:', parseErr); if (!isResolvedOrRejected) { isResolvedOrRejected = true; reject(parseErr); } imap.end(); } }); }); }; imap.on('mail', onMail); }); }); // 超时处理:主动关闭连接并返回null setTimeout(() => { if (!isResolvedOrRejected) { isResolvedOrRejected = true; imap.end(); resolve(null); } }, timeout); }); } function sleep(minSeconds, maxSeconds) { const sleepDuration = Math.floor(Math.random() * (maxSeconds - minSeconds + 1) + minSeconds) * 1000; return new Promise(resolve => setTimeout(resolve, sleepDuration)); } module.exports = { waitForEmail };
关键修复说明
- 移除了多余的嵌套Promise,修复了语法结构问题。
- 将邮件解析改为async/await写法,提升代码可读性与时序控制。
- 收到新邮件后立即移除
mail事件监听,避免重复触发。 - 超时处理中主动调用
imap.end()关闭连接,防止资源泄漏。 - 完善错误过滤逻辑,已完成resolve/reject后忽略后续非关键错误。
- 给
sleep添加了await,保证延迟逻辑生效(若不需要可直接删除该代码)。
内容的提问来源于stack exchange,提问作者Bella Smith
相关产品推荐
相关产品推荐

