You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js IMAP邮件监听函数执行后出现ECONNREFUSED错误排查

问题分析与修复方案

错误根源

结合你的代码与控制台输出,核心问题如下:

  1. 多余嵌套Promise破坏代码结构:waitForEmail主Promise内部的嵌套Promise完全无意义,你试图用return阻止后续代码,但该return仅作用于内部Promise的回调函数,无法终止主Promise内的逻辑执行,还导致语法不完整。
  2. 异步sleep未做await处理:调用sleep(5,6)时未添加await,导致resolve(emailInfo)在sleep完成前就执行,虽不直接引发连接错误,但会造成逻辑时序混乱。
  3. 连接关闭后的错误未被妥善过滤:调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 09:33:19