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

Next.js中tRPC调用node-imap获取邮箱OTP的异常问题

Next.js + tRPC + node-imap 提取OTP的问题解决

问题1:调用trpc.getOtp.useQuery()返回空数组

原因

遍历邮件时使用了mailParser.simpleParser的回调版本,但未等待所有解析完成就执行了await imap.end(),读取全局OTPcodes数组时解析还没完成,导致返回空数组。

解决方案

将mailParser.simpleParser封装为Promise形式,用Promise.all等待所有邮件解析完成,同时把OTPcodes移到run函数内部,避免全局变量污染。

问题2:run()自动重复执行/调用process.exit()出现ECONNRESET

原因

  • 全局变量OTPcodes不会重置,每次请求都会累加数据,且Next.js开发模式下的热重载可能触发重复执行。
  • process.exit()会直接终止Node.js进程,此时imap连接未正常关闭,导致抛出ECONNRESET错误。

解决方案

  • 放弃全局变量存储OTP,将数组放到run函数内部,每次请求重新生成。
  • 移除process.exit(),确保所有异步操作完成后再正常关闭imap连接。

修改后的完整代码

async function run() {
    // 把OTPcodes移到函数内部,避免全局污染
    const OTPcodes: (string | null)[] = [];
    const config = {
        imap: {
            user: process.env.NEXT_PUBLIC_YMAIL_USER,
            password: process.env.NEXT_PUBLIC_YMAIL_PASSWORD,
            host: process.env.NEXT_PUBLIC_YMAIL_HOST,
            port: process.env.NEXT_PUBLIC_EMAIL_PORT,
            tls: process.env.NEXT_PUBLIC_EMAIL_TLS,
        },
        debug: logger.info.bind(logger),
    };

    const imap = new MyImap(config);
    const result = await imap.connect();
    logger.info(`result: ${result}`);
    const boxName = await imap.openBox();
    logger.info(`boxName: ${boxName}`);

    const criteria = [['HEADER', 'SUBJECT', ' Account']];
    const emails = await imap.fetchEmails(criteria);

    // 把simpleParser封装成Promise,用Promise.all等待所有解析完成
    await Promise.all(emails.map(async (email) => {
        const parsed = await new Promise((resolve, reject) => {
            mailParser.simpleParser(email.body, (err, parsed) => {
                if (err) reject(err);
                else resolve(parsed);
            });
        });
        const otp = matchOTP(parsed.text);
        console.log("OTP "+ otp);
        if (otp) OTPcodes.push(otp);
    }));

    await imap.end();
    return OTPcodes; // 直接返回结果,不用全局变量
}

function matchOTP(email: string){
  const regex = /\b(?![A-Z]{5}\b)[A-Z0-9]{5}\b/;
  const match = email.match(regex);
  return match && match[0];
}

async function parseEmails(){
    try {
        return await run(); // 直接返回run的结果
    } catch (error) {
        logger.error(error);
        throw error; // 抛出错误让tRPC处理,不要终止进程
    }
}

const appRouter = router({
   getOTP: publicProcedure.query(async () => {
    const otpCodes = await parseEmails();
    console.log("Array of OTP "+JSON.stringify(otpCodes));
    return otpCodes;
  }),
});

export type AppRouter = typeof appRouter;

export default trpcNext.createNextApiHandler({
  router: appRouter,
  createContext: () => ({}),
});

内容的提问来源于stack exchange,提问作者masu.mo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 08:27:38