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

如何在Cypress中使用Node.js IMAP库实现邮件重试抓取?

实现Cypress中IMAP邮件抓取的重试机制

要解决未找到邮件时的重试问题,我们可以通过Promise化IMAP查询逻辑 + 异步重试循环来实现,具体步骤如下:

1. 重构IMAP查询为Promise函数

将原来的回调式IMAP操作封装为返回Promise的函数,方便后续用async/await处理重试。当未找到邮件时主动抛出错误,触发重试逻辑。

const Imap = require('imap');
const { inspect } = require('util');
const fs = require('fs');

// 单次邮件查询逻辑,返回Promise
const fetchEmailOnce = (filter) => {
  return new Promise((resolve, reject) => {
    // 初始化IMAP连接(根据你的邮箱配置修改)
    const imap = new Imap({
      user: '你的邮箱地址',
      password: '邮箱密码/应用密码',
      host: 'imap服务商地址', // 比如imap.gmail.com、imap.qq.com
      port: 993,
      tls: true
    });

    let emailContent = null;

    imap.once('ready', () => {
      imap.openBox('INBOX', false, (err, box) => {
        if (err) {
          imap.end();
          return reject(err);
        }

        imap.search(filter, (err, results) => {
          if (err) {
            imap.end();
            return reject(err);
          }

          // 未找到邮件,抛出错误触发重试
          if (results.length === 0) {
            imap.end();
            return reject(new Error('未找到符合条件的邮件'));
          }

          // 抓取邮件内容
          const f = imap.fetch(results, { bodies: '1', markSeen: true });
          f.on('message', (msg, seqno) => {
            msg.on('body', (stream, info) => {
              let buffer = '';
              stream.on('data', (chunk) => {
                buffer += chunk.toString('utf8');
              });
              stream.once('end', () => {
                if (info.which === '1') {
                  emailContent = buffer;
                }
              });
            });
          });

          f.once('error', (err) => {
            imap.end();
            reject(err);
          });

          f.once('end', () => {
            imap.end();
            emailContent ? resolve(emailContent) : reject(new Error('邮件内容提取失败'));
          });
        });
      });
    });

    imap.once('error', reject);
    imap.once('end', () => console.log('IMAP连接已关闭'));
    imap.connect();
  });
};

2. 实现重试逻辑

写一个异步重试函数,循环调用上面的单次查询函数,直到找到邮件或达到最大重试次数。

// 重试函数:maxRetries为最大重试次数,delayMs为每次重试间隔(毫秒)
const retryFetchEmail = async (filter, maxRetries = 100, delayMs = 500) => {
  let attempt = 0;
  while (attempt < maxRetries) {
    try {
      const email = await fetchEmailOnce(filter);
      return email; // 找到邮件,返回结果
    } catch (err) {
      attempt++;
      console.log(`重试 ${attempt}/${maxRetries}: ${err.message}`);
      if (attempt >= maxRetries) {
        throw new Error(`经过${maxRetries}次重试后仍未找到邮件`);
      }
      // 等待指定时间后重试
      await new Promise(resolve => setTimeout(resolve, delayMs));
    }
  }
};

3. 更新Cypress Task

将重试逻辑集成到Cypress任务中,供测试命令调用。

const myTask = {
  async fetchEmail(filterParams) {
    try {
      // 这里可以调整重试次数和间隔,比如改成50次重试、每次间隔1000ms
      const emailContent = await retryFetchEmail(filterParams, 100, 500);
      return emailContent;
    } catch (err) {
      throw err; // 抛出错误,Cypress测试会捕获并标记失败
    }
  }
};

// 在Cypress配置中注册任务(以Cypress 10+为例)
module.exports = defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      on('task', myTask);
    },
  },
});

4. 修正Cypress命令

修正原命令中的拼写错误(fechEmail改为fetchEmail),确保正确接收返回结果。

Cypress.Commands.add('fetchEmail', () => {
  return cy.task('fetchEmail', ['UNSEEN', ['SUBJECT', 'stone']])
    .then(emailContent => {
      // 可选:在这里处理邮件内容,比如提取验证码、链接等
      return emailContent;
    });
});

关键说明

  • 每次重试都会重新建立IMAP连接,避免连接超时或状态异常。
  • 可以根据需求调整maxRetries(50-100次)和delayMs(比如500ms-1000ms)。
  • 如果所有重试都失败,测试会抛出错误并终止,符合“邮件超时未收到则测试失败”的预期。
  • 若需要提取邮件中的特定内容(如验证码),可在fetchEmailOnce中处理后返回对应值,而非整个邮件内容。

内容的提问来源于stack exchange,提问作者Dragan Stanisavljevic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 18:05:31