nodemailer分块发送超大附件时如何匹配pdfBuffer与分块附件数组
nodemailer附件分块后Buffer匹配逻辑失效排查
业务背景
- 基于nodemailer实现邮件发送能力,设置附件总大小阈值
LIMIT_ATTACHMENTS:发送前计算所有附件总大小,超阈值时调用lodash_.chunk方法拆分附件为多个子块,分多封邮件发送,每封邮件保留相同主题、正文,仅携带对应分块内的附件。 - 附件拆分前执行
prepareAttachments方法:接口拉取数据生成PDF Buffer,组装为邮件附件的content字段,同时将原始BufferXSolicitudDTO格式数组赋值给类属性,供后续匹配逻辑使用。 - 预期逻辑:每个附件分块处理时,匹配当前分块内附件对应的原始PDF Buffer与类属性存储的原始数组元素的
pdfBuffer字段,两者一致时执行预设业务操作。 - 异常现象:判断逻辑
if (element.pdfBuffer === attachmentMap)始终无法进入相等分支。
问题根因
- 比较对象类型完全不匹配
代码中attachmentMap是通过attachment.map(element => element.content)生成的Buffer实例数组,但判断逻辑拿单个原始DTO元素的pdfBuffer(单个Buffer实例)和整个数组做===比较,数据类型不一致,永远不可能返回true。 - Buffer比较方式错误
JavaScript中===对引用类型(包括Buffer、对象、数组)的比较规则是校验内存引用地址,就算两个Buffer的二进制内容完全一致,只要不是同一个内存引用,===比较结果永远为false。 - 属性名拼写笔误
prepareAttachments方法中给原始DTO数组赋值的属性是this.getCantidad,但后续匹配逻辑读取的是this.getAmount,赋值和读取的不是同一个属性,就算比较逻辑写对也拿不到原始数据。 - 附件拆分逻辑参数错误(附带问题)
_.chunk方法第二个参数是每个子块的元素个数,但代码中传入的chunkSplit是计算出来的预期拆分块数,会导致拆分后的子块附件大小仍然可能超过阈值,不符合大小管控的设计目标。
修复方案
- 统一类属性命名,修正拼写错误,确保
prepareAttachments赋值和后续逻辑读取的是同一个属性。 - 调整匹配逻辑遍历规则:逐个遍历当前分块的附件content,和原始DTO数组中每个元素的pdfBuffer做比对,不要拿单值和数组比较。
- Buffer内容比对使用Node.js内置的
Buffer.equals()方法,该方法逐字节比对Buffer二进制内容,不依赖内存引用地址,只要内容一致就返回true。 - 修正附件拆分逻辑,按附件大小累加拆分,确保每个子块总大小不超过阈值,不要按元素个数平均拆分。
修复后核心代码片段
替换原else分支中匹配逻辑相关代码:
// 删除原错误匹配逻辑,替换为以下内容 console.log('original DTO list', this.getAmount); // 遍历当前分块的每个附件 for (const att of attachment) { // 遍历原始DTO列表做匹配 for (const element of this.getAmount) { // 先校验两者都是合法Buffer,再做内容比对 if ( Buffer.isBuffer(att.content) && Buffer.isBuffer(element.pdfBuffer) && att.content.equals(element.pdfBuffer) ) { console.log('match success, execute preset action'); // 此处写入需要执行的预设业务逻辑 } } } const link = ` (${index + 1}/${attachmentsChunk.length - 1})`; const newContext = { getCurrent: link, ...context } return this.prepareEmail({ para: to, asunto: ` ${subject} (Correo ${index + 1}/${attachmentsChunk.length - 1})`, plantilla: template, contexto: newContext, }, attachment);
附件拆分逻辑修正参考
原按元素个数拆分的逻辑替换为按大小累加拆分,确保单块不超阈值:
// 替换原chunkSplit、attachmentsChunk计算逻辑 const attachmentsChunk: EmailAttachment[][] = []; let currentChunk: EmailAttachment[] = []; let currentChunkSize = 0; for (const att of attachments) { const attSize = Buffer.isBuffer(att.content) ? att.content.length : 0; // 单个附件超过阈值的情况走原有上传Drive逻辑即可 if (currentChunkSize + attSize > this.LIMIT_ATTACHMENTS && currentChunk.length > 0) { attachmentsChunk.push(currentChunk); currentChunk = []; currentChunkSize = 0; } currentChunk.push(att); currentChunkSize += attSize; } // 把最后一个块加入列表 if (currentChunk.length > 0) { attachmentsChunk.push(currentChunk); }
内容的提问来源于stack exchange,提问作者Izlia
相关产品推荐
相关产品推荐

