使用xhtml2pdf生成PDF并作为邮件附件发送的问题
解决方案:Django模板生成PDF并作为邮件附件发送
问题核心
需实现从模板生成PDF并自动作为邮件附件发送的功能,目前单独的PDF生成和邮件发送功能均正常,但结合时出现问题:
- 第一段代码能生成PDF,但无法成功附加到邮件
- 第二段代码能生成可下载的PDF,但无法直接用于邮件附件
错误原因
- 不必要的Base64编码:第一段代码中对PDF二进制内容做了Base64编码,但Django的
EmailMessage.attach()方法需要的是原始二进制数据,而非编码后的字符串 - 错误的MIME类型:附件的MIME类型填写为
pdf,正确值应为application/pdf - 缺少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
相关产品推荐
相关产品推荐

