如何将React-PDF生成的PDF文件通过Nodemailer添加至邮件附件
解决React客户端生成PDF并通过Nodemailer作为邮件附件发送的问题
问题核心
你当前的代码存在两个关键缺失:
- 客户端仅直接下载PDF,未将文件数据传递给后端
- 后端Nodemailer配置中缺少附件的实际内容
以下是完整的前后端修改方案:
一、客户端代码修改(生成PDF并传递给后端)
修改generatePDF函数,取消直接下载,先获取PDF的Blob数据,再通过FormData发送到后端接口:
import ReactDOMServer from "react-dom/server"; import html2pdf from "html2pdf.js/dist/html2pdf.min"; import Pdf from "./Pdf"; async function generatePDF(userProfile) { const printElement = ReactDOMServer.renderToString( Pdf({ profilepicture: userProfile.profilepicture, firstname: userProfile.firstname, lastname: userProfile.lastname, designation: userProfile.designation, email: userProfile.email, phonenumber: userProfile.phonenumber, summary: userProfile.summary, experience: userProfile.experience, education: userProfile.education, projects: userProfile.projects, technologies: userProfile.technologies }) ); const opt = { margin: [15, 0, 30, 0], // top, left, bottom, right enableLinks: true, filename: "pdfreport", html2canvas: { useCORS: true }, jsPDF: {}, }; try { const pdf = await html2pdf() .from(printElement) .set(opt) .toPdf() .get("pdf"); pdf.setPage(1); // 获取PDF的Blob格式数据 const pdfBlob = pdf.output('blob'); // 构建FormData,包含PDF文件和邮件参数 const formData = new FormData(); formData.append('pdfFile', pdfBlob, 'pdfreport.pdf'); // 指定文件名及后缀 formData.append('send_to', '目标收件人邮箱'); formData.append('subject', '个人PDF报告'); formData.append('message', '<p>这是生成的个人PDF报告,请查收</p>'); formData.append('sent_from', '你的发件人邮箱'); formData.append('reply_to', '回复邮箱'); // 发送请求到后端邮件接口 const response = await fetch('/api/send-email-with-pdf', { method: 'POST', body: formData }); if (response.ok) { console.log('邮件发送成功'); // 可选:如果需要同时让用户下载PDF,取消下面注释 // pdf.save(); } else { console.error('邮件发送失败'); } } catch (err) { console.error('生成PDF或发送请求出错:', err); } } export default { generatePDF };
二、后端代码修改(接收PDF并通过Nodemailer发送)
需要先安装multer处理FormData文件上传,再修改邮件发送逻辑:
1. 安装依赖
npm install multer
2. 修改后端代码
import nodemailer from "nodemailer"; import express from 'express'; import multer from 'multer'; const app = express(); // 配置multer为内存存储,直接获取文件buffer const storage = multer.memoryStorage(); const upload = multer({ storage: storage }); const sendEmail = async (subject, message, send_to, sent_from, reply_to, pdfFile) => { const transporter = nodemailer.createTransport({ host: process.env.EMAIL_HOST, port: 465, secure: true, // 注意这里是布尔值,不是字符串"true" auth: { user: process.env.EMAIL_USER, pass: process.env.EMAIL_PASS, }, }); const options = { from: sent_from, to: send_to, replyTo: reply_to, subject: subject, html: message, attachments: [{ filename: pdfFile.originalname, // 使用上传时指定的文件名 content: pdfFile.buffer, // 内存中的PDF文件buffer contentType: 'application/pdf' // 指定MIME类型,确保邮件客户端识别为PDF }] }; try { const info = await transporter.sendMail(options); console.log(info); return info; } catch (err) { console.log(err); throw err; } }; // 定义接收PDF和邮件参数的接口 app.post('/api/send-email-with-pdf', upload.single('pdfFile'), async (req, res) => { try { const { subject, message, send_to, sent_from, reply_to } = req.body; const pdfFile = req.file; if (!pdfFile) { return res.status(400).json({ error: '未上传PDF文件' }); } await sendEmail(subject, message, send_to, sent_from, reply_to, pdfFile); res.status(200).json({ message: '邮件发送成功' }); } catch (err) { res.status(500).json({ error: '邮件发送失败', details: err.message }); } }); export default sendEmail;
三、关键注意事项
- 后端Nodemailer配置中
secure参数必须是布尔值true,而非字符串 - 客户端传递FormData时,需给PDF文件加上
.pdf后缀,避免邮件附件格式识别错误 - 若需要同时让用户下载PDF,在请求成功后调用
pdf.save()即可 - 确保后端接口路径与客户端请求路径一致,且已配置CORS(如果前后端跨域)
内容的提问来源于stack exchange,提问作者A.Z.M
相关产品推荐
相关产品推荐

