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

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 });
  }
});

关键问题解决点

  1. 动态重命名:Print.printToFileAsync的fileName参数可直接指定自定义文件名,无需额外重命名操作。
  2. 文件不存在问题:前端本地URI仅设备内部可访问,后端无法直接读取,转为Base64是跨设备通用的传输方案。
  3. 用户关闭后触发:expo-file-viewer的openAsync会在用户关闭文件后完成Promise,完美契合"关闭后自动发送"的需求。

内容的提问来源于stack exchange,提问作者yesIamFaded

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 17:15:27