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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 18:01:20