使用Nodemailer动态发送Zip文件的技术方案问询
问题描述
我有一批需通过JavaScript压缩为Zip格式的附件,要将该Zip文件作为邮件附件发送给用户。目前尝试用archiver库压缩文件,但直接将生成的Zip对象加入Nodemailer的附件数组时文件会损坏,因Nodemailer要求提供文件路径。请问是否有无需在本地或服务器保存副本,即可动态生成Zip文件并用于发送给客户端的方法?
尝试的代码
var zip = Archiver('zip'); zip.append(file_to_be_zipped, { name: 'file2.txt' }) .finalize(); // 邮件配置 { from: configuration.data.from, to: req.body.to.join(';'), cc: req.body.cc && req.body.cc.join(';'), bcc: req.body.bcc && req.body.bcc.join(';'), subject: subject, html: body, attachments: zip }
解决方法
不用保存到本地,直接通过流(Stream)或者Buffer把archiver生成的zip内容传给Nodemailer即可——Nodemailer的attachments支持直接传入流或Buffer,不需要文件路径。
方法1:用PassThrough流传递(推荐,适合大文件)
Node.js内置的stream.PassThrough可以作为中转流,把archiver的输出流导入后直接传给Nodemailer,避免占用过多内存:
const { PassThrough } = require('stream'); const archiver = require('archiver'); const nodemailer = require('nodemailer'); // 创建中转流 const passThroughStream = new PassThrough(); // 初始化zip实例并添加文件 const zip = archiver('zip', { zlib: { level: 9 } }); // 可调整压缩等级 zip.append(file_to_be_zipped, { name: 'file2.txt' }); // 处理压缩错误 zip.on('error', (err) => { throw err; }); // 将zip流导入中转流 zip.pipe(passThroughStream); zip.finalize(); // 邮件配置 const mailOptions = { from: configuration.data.from, to: req.body.to.join(';'), cc: req.body.cc && req.body.cc.join(';'), bcc: req.body.bcc && req.body.bcc.join(';'), subject: subject, html: body, attachments: [ { filename: '附件压缩包.zip', // 邮件中显示的文件名 content: passThroughStream, // 直接传入中转流 contentType: 'application/zip' // 指定MIME类型 } ] }; // 发送邮件 const transporter = nodemailer.createTransport(/* 你的邮箱配置 */); transporter.sendMail(mailOptions, (err, info) => { if (err) { console.error(err); } else { console.log('邮件发送成功:', info.response); } });
方法2:收集成Buffer后传递(适合小文件)
如果压缩内容不大,可以先把zip流收集成Buffer,再传给Nodemailer:
const archiver = require('archiver'); const nodemailer = require('nodemailer'); // 初始化zip实例 const zip = archiver('zip', { zlib: { level: 9 } }); zip.append(file_to_be_zipped, { name: 'file2.txt' }); // 收集Buffer片段 let zipBuffer = []; zip.on('data', (chunk) => zipBuffer.push(chunk)); zip.on('end', () => { zipBuffer = Buffer.concat(zipBuffer); // 邮件配置 const mailOptions = { from: configuration.data.from, to: req.body.to.join(';'), cc: req.body.cc && req.body.cc.join(';'), bcc: req.body.bcc && req.body.bcc.join(';'), subject: subject, html: body, attachments: [ { filename: '附件压缩包.zip', content: zipBuffer, // 传入拼接后的Buffer contentType: 'application/zip' } ] }; // 发送邮件 const transporter = nodemailer.createTransport(/* 你的邮箱配置 */); transporter.sendMail(mailOptions, (err, info) => { if (err) console.error(err); else console.log('邮件发送成功:', info.response); }); }); // 处理压缩错误 zip.on('error', (err) => { throw err; }); zip.finalize();
关键注意点
- Nodemailer的
attachments对象支持content字段,可接受字符串、Buffer或流,这是无需本地存储的核心。 - 必须监听archiver的
error事件,避免压缩失败导致流程阻塞。 - 如需压缩多个文件,多次调用
zip.append()即可,每个调用可指定不同的文件名。
内容的提问来源于stack exchange,提问作者Uma
相关产品推荐
相关产品推荐

