Next.js集成node-IMAP调用API时邮件丢失问题求助
邮件丢失问题排查与修复
核心问题分析
你的代码存在两个关键逻辑错误,直接导致邮件丢失,且生产环境因网络延迟问题更严重:
错误存储异步函数而非Promise
在msg.on('body')中,你将异步函数存入messages数组,但Promise.all只会处理Promise实例,不会自动执行这些函数。这意味着大部分邮件的解析逻辑根本没有运行,自然不会出现在结果中。fetch的end事件触发过早
生产环境网络延迟更高,node-imap的seq.fetch触发end事件时,部分邮件的body事件可能还未触发(网络传输慢导致),此时messages数组还没收集到所有邮件的解析任务,最终结果就会缺失这些邮件。
修复后的代码
import Imap from 'node-imap' import { simpleParser } from 'mailparser' import { inspect } from 'util' export default async function handler(req, res) { try { const cred = req.body const imap = new Imap({ user: cred.email, password: cred.password, host: cred.server, port: 993, tls: true }) imap.on('ready', async function () { try { const messages = await fetchMessages(imap) res.status(200).json(messages) } catch (error) { console.error('Error fetching messages:', error) res.status(500).json({ error: 'An error occurred while fetching messages' }) } finally { imap.end() } }) imap.once('error', function (err) { console.error('IMAP Error:', err) res.status(500).json({ error: 'An error occurred while connecting to the mail server' }) }) imap.once('end', function () { console.log('Connection ended') }) imap.connect() } catch (error) { console.error('Error:', error) res.status(500).json({ error: 'An unexpected error occurred' }) } } async function fetchMessages(imap) { return new Promise((resolve, reject) => { imap.openBox('INBOX', true, (err, box) => { if (err) { reject(err) return } const messagePromises = [] const f = imap.seq.fetch('1:*', { bodies: '', struct: true }) f.on('message', function (msg, seqno) { // 为每封邮件创建一个Promise,确保完整解析后再加入数组 const messagePromise = new Promise((resolveMsg, rejectMsg) => { let parsedEmail = null let emailAttributes = null msg.on('body', async function (stream, info) { try { const buffer = await parseMessage(stream) parsedEmail = await simpleParser(buffer) // 当属性和正文都就绪时,返回完整邮件数据 if (emailAttributes) { resolveMsg({ ...parsedEmail, attributes: emailAttributes }) } } catch (error) { console.error('Error parsing message body:', error) rejectMsg(error) } }) msg.on('attributes', function (attrs) { emailAttributes = attrs // 当属性和正文都就绪时,返回完整邮件数据 if (parsedEmail) { resolveMsg({ ...parsedEmail, attributes: emailAttributes }) } }) msg.on('error', function (err) { console.error('Message error:', err) rejectMsg(err) }) }) messagePromises.push(messagePromise) }) f.on('error', function (err) { console.error('Fetch error:', err) reject(err) }) f.on('end', async function () { console.log('Done fetching all message metadata!') // 等待所有邮件的解析Promise完成 const parsedMessages = await Promise.all(messagePromises) console.log('Done downloading all messages!') resolve(parsedMessages) }) }) }) } function parseMessage(stream) { return new Promise((resolve, reject) => { let buffer = '' stream.on('data', function (chunk) { buffer += chunk.toString('utf8') }) stream.on('end', function () { resolve(buffer) }) stream.on('error', function (err) { reject(err) }) }) }
关键修改说明
- 为每封邮件创建独立Promise:在
message事件中,给每封邮件生成一个Promise,等待body和attributes都处理完成后再resolve,确保不会遗漏任何邮件的解析。 - 存储Promise而非异步函数:将每封邮件的Promise直接存入
messagePromises数组,Promise.all会正确等待所有Promise完成。 - 处理邮件内部的错误:新增
msg.on('error')捕获单封邮件的解析错误,避免单个邮件失败导致整个任务终止。
内容的提问来源于stack exchange,提问作者sanal ms
相关产品推荐
相关产品推荐

