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

使用xhtml2pdf生成PDF并作为邮件附件发送的问题

解决方案:Django模板生成PDF并作为邮件附件发送

问题核心

需实现从模板生成PDF并自动作为邮件附件发送的功能,目前单独的PDF生成和邮件发送功能均正常,但结合时出现问题:

  • 第一段代码能生成PDF,但无法成功附加到邮件
  • 第二段代码能生成可下载的PDF,但无法直接用于邮件附件

错误原因

  1. 不必要的Base64编码:第一段代码中对PDF二进制内容做了Base64编码,但Django的EmailMessage.attach()方法需要的是原始二进制数据,而非编码后的字符串
  2. 错误的MIME类型:附件的MIME类型填写为pdf,正确值应为application/pdf
  3. 缺少PDF生成错误检查:未验证pisa是否成功生成PDF,可能发送损坏的文件

修正后的完整代码

def vendorwopdf(request, *args, **kwargs):
    wonumb = kwargs.get('WorkOderNumb')
    
    # 获取工单数据
    searchresult = WorkOrders.objects.get(WorkOderNumb=wonumb)
    
    # 渲染HTML模板
    template = get_template("workorders/workorderpdf.html")
    html = template.render({"searchresult": searchresult})
    
    # 生成PDF到内存中(无需保存到服务器)
    result = io.BytesIO()
    pisa_status = pisa.CreatePDF(html, dest=result)
    
    # 检查PDF生成是否成功
    if pisa_status.err:
        return HttpResponse('PDF生成出错: <pre>' + html + '</pre>')
    
    # 重置文件指针到开头
    result.seek(0)
    pdf_content = result.read()
    
    # 构建邮件
    email = EmailMessage(
        f"RE: Authorized Workorder {wonumb}",
        "Greetings please find attached the approved workorder",
        "no-reply@example.ca",
        ["no-reply@example.ca"],
    )
    
    # 附加PDF:使用原始二进制数据,正确MIME类型
    email.attach("workorder.pdf", pdf_content, "application/pdf")
    
    # 发送邮件
    email.send()
    
    return render(request, 'workorders/vendorwo.html', {"searchresult": searchresult})

关键说明

  • 无需保存到服务器:通过io.BytesIO()在内存中生成和存储PDF,直接传递给邮件附件,避免磁盘IO操作
  • 正确的附件参数:attach()方法的三个参数分别是:文件名、原始二进制内容、标准MIME类型
  • 错误检查:添加pisa_status.err判断,提前拦截PDF生成失败的情况

额外优化建议

  • 用try-except包裹email.send(),捕获邮件发送失败的异常并处理
  • 若模板中使用本地静态图片,可配置pisa的link_callback参数,确保图片能被正确加载

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 14:20:35