Expo React Native生成PDF并通过Nodemailer发送的问题求助
解决方案:Expo React Native 生成自定义PDF + 后台自动发送流程
核心思路
前端生成自定义命名的PDF后,将文件内容转为Base64格式传给后端(避免设备本地URI无法被后端访问的问题),同时打开PDF供用户查看,待用户关闭文件后触发Nodemailer发送逻辑。
一、生成自定义命名PDF并转换为Base64
使用Print.printToFileAsync直接指定文件名,再通过FileSystem读取文件内容转为Base64:
import * as Print from 'expo-print'; import * as FileSystem from 'expo-file-system'; const generatePDF = async (htmlContent) => { // 生成PDF,指定自定义文件名和存储目录 const pdfResult = await Print.printToFileAsync({ html: htmlContent, fileName: '自定义文件名.pdf', directory: FileSystem.documentDirectory, base64: false }); // 将PDF文件转为Base64,用于传给后端 const pdfBase64 = await FileSystem.readAsStringAsync(pdfResult.uri, { encoding: FileSystem.EncodingType.Base64 }); return { fileUri: pdfResult.uri, fileBase64: pdfBase64, fileName: '自定义文件名.pdf' }; };
二、打开PDF并在用户关闭后触发发送
使用expo-file-viewer打开PDF,它会在用户关闭文件后resolve Promise,此时执行发送逻辑:
import * as FileViewer from 'expo-file-viewer'; const handlePDFWorkflow = async () => { // 替换为你的HTML内容 const html = `<html><body><h1>业务内容PDF</h1></body></html>`; // 生成PDF并获取Base64内容 const { fileUri, fileBase64, fileName } = await generatePDF(html); // 打开PDF,等待用户关闭 await FileViewer.openAsync(fileUri); // 用户关闭文件后,调用后端接口发送邮件 await sendPDFToBackend(fileBase64, fileName); }; // 调用后端接口的函数 const sendPDFToBackend = async (base64, fileName) => { try { await fetch('你的后端接口地址', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ pdfBase64: base64, fileName: fileName }) }); } catch (err) { console.error('发送失败:', err); } };
三、后端接收Base64并发送邮件(Nodemailer)
后端将Base64转为Buffer,直接作为邮件附件发送:
const nodemailer = require('nodemailer'); // 你的Nodemailer配置(已测试通过的部分) const transporter = nodemailer.createTransport({ host: '你的SMTP服务器', port: 587, secure: false, auth: { user: '你的邮箱账号', pass: '你的邮箱授权码' } }); // 处理前端请求的接口 app.post('/send-pdf', async (req, res) => { const { pdfBase64, fileName } = req.body; // 将Base64转为Buffer const pdfBuffer = Buffer.from(pdfBase64, 'base64'); try { await transporter.sendMail({ from: '发送方邮箱', to: '接收方邮箱', subject: '自动发送的PDF文件', text: '附件为生成的PDF', attachments: [ { filename: fileName, content: pdfBuffer, contentType: 'application/pdf' } ] }); res.status(200).json({ msg: '邮件发送成功' }); } catch (err) { res.status(500).json({ msg: '发送失败', error: err.message }); } });
关键问题解决点
- 动态重命名:
Print.printToFileAsync的fileName参数可直接指定自定义文件名,无需额外重命名操作。 - 文件不存在问题:前端本地URI仅设备内部可访问,后端无法直接读取,转为Base64是跨设备通用的传输方案。
- 用户关闭后触发:
expo-file-viewer的openAsync会在用户关闭文件后完成Promise,完美契合"关闭后自动发送"的需求。
内容的提问来源于stack exchange,提问作者yesIamFaded
相关产品推荐
相关产品推荐

