【问题标题】:Generate PDF from html template and send via Email in Django从 html 模板生成 PDF 并在 Django 中通过电子邮件发送
【发布时间】:2018-08-19 09:09:52
【问题描述】:

我正在尝试使用Weasyprint python 包从 HTML 模板生成一个 pdf 文件,我需要使用它通过电子邮件发送。

这是我尝试过的:

def send_pdf(request):
minutes = int(request.user.tagging.count()) * 5
testhours = minutes / 60
hours = str(round(testhours, 3))
user_info = {
    "name": str(request.user.first_name + ' ' + request.user.last_name),
    "hours": str(hours),
    "taggedArticles": str(request.user.tagging.count())
}
html = render_to_string('users/certificate_template.html',
                        {'user': user_info})
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'filename=certificate_{}'.format(user_info['name'] + '.pdf')
pdf = weasyprint.HTML(string=html).write_pdf(response, )
from_email = 'our_business_email_address'
to_emails = ['Reciever1', 'Reciever2']
subject = "Certificate from INC."
message = 'Enjoy your certificate.'
email = EmailMessage(subject, message, from_email, to_emails)
email.attach("certificate.pdf", pdf, "application/pdf")
email.send()
return HttpResponse(response, content_type='application/pdf')

但它返回错误为TypeError: expected bytes-like object, not HttpResponse

如何从 HTML 模板生成 pdf 文件并将其发送到电子邮件?

更新:现在有了这个更新的代码,它正在生成 pdf 并发送一封电子邮件,但是当我从收到的电子邮件中打开附加的 pdf 文件时,它显示unsupported file formate data

这是更新后的代码:

def send_pdf(request):
minutes = int(request.user.tagging.count()) * 5
testhours = minutes / 60
hours = str(round(testhours, 3))
user_info = {
    "name": str(request.user.first_name + ' ' + request.user.last_name),
    "hours": str(hours),
    "taggedArticles": str(request.user.tagging.count())
}
html = render_to_string('users/certificate_template.html',
                        {'user': user_info})
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'filename=certificate_{}'.format(user_info['name']) + '.pdf'
pdf = weasyprint.HTML(string=html).write_pdf()
from_email = 'arycloud7@icloud.com'
to_emails = ['abdul12391@gmail.com', 'arycloud7@gmail.com']
subject = "Certificate from Nami Montana"
message = 'Enjoy your certificate.'
email = EmailMessage(subject, body=pdf, from_email=settings.EMAIL_HOST_USER, to=to_emails)
# email.attach("certificate.pdf", pdf, "application/pdf")
email.content_subtype = "pdf"  # Main content is now text/html
email.encoding = 'ISO-8859-1'
email.send()
return HttpResponse(pdf, content_type='application/pdf')

请帮帮我!

提前致谢!

【问题讨论】:

    标签: python django django-templates weasyprint python-pdfkit


    【解决方案1】:

    以@Rishabh gupta 答案为基础:

    import io
    
    from django.template.loader import render_to_string
    from django.core.mail import EmailMultiAlternatives
    from weasyprint import HTML
    
    context = { "name": 'Hello', }
    html_string = render_to_string('myapp/report.html', context)
    html = HTML(string=html_string)
    buffer = io.BytesIO()
    html.write_pdf(target=buffer)
    pdf = buffer.getvalue()
    
    email_message = EmailMultiAlternatives(
        to=("youremailadress@gmail.com",),
        subject="subject test print",
        body="heres is the body",
    )
    filename = 'test.pdf'
    mimetype_pdf = 'application/pdf'
    email_message.attach(filename, pdf, mimetype_pdf)
    email_message.send(fail_silently=False)  # TODO zzz mabye change this to True
    
    

    【讨论】:

      【解决方案2】:

      此代码适用于我

          template = get_template('admin/invoice.html')
          context = {
              "billno": bill_num,
              "billdate": bill_date,
              "patientname": patient_name,
              "totalbill": total_bill,
              "billprocedure": invoice_cal,
      
          }
      
          html  = template.render(context)
          result = BytesIO()
          pdf = pisa.pisaDocument(BytesIO(html.encode("ISO-8859-1")), result)#, link_callback=fetch_resources)
          pdf = result.getvalue()
          filename = 'Invoice.pdf'
          to_emails = ['receiver@gmail.com']
          subject = "From CliMan"
          email = EmailMessage(subject, "helloji", from_email=settings.EMAIL_HOST_USER, to=to_emails)
          email.attach(filename, pdf, "application/pdf")
          email.send(fail_silently=False)
      

      【讨论】:

        【解决方案3】:

        这是上述代码的完整工作版本:

            user_infor = ast.literal_eval(ipn_obj.custom)
            if int(user_infor['taggedArticles']) > 11:
                # generate and send an email with pdf certificate file to the user's email
                user_info = {
                    "name": user_infor['name'],
                    "hours": user_infor['hours'],
                    "taggedArticles": user_infor['taggedArticles'],
                    "email": user_infor['email'],
                }
                html = render_to_string('users/certificate_template.html',
                                        {'user': user_info})
                response = HttpResponse(content_type='application/pdf')
                response['Content-Disposition'] = 'filename=certificate_{}'.format(user_info['name']) + '.pdf'
                pdf = weasyprint.HTML(string=html, base_url='http://8d8093d5.ngrok.io/users/process/').write_pdf(
                    stylesheets=[weasyprint.CSS(string='body { font-family: serif}')])
                to_emails = [str(user_infor['email'])]
                subject = "Certificate from Nami Montana"
                email = EmailMessage(subject, body=pdf, from_email=settings.EMAIL_HOST_USER, to=to_emails)
                email.attach("certificate_{}".format(user_infor['name']) + '.pdf', pdf, "application/pdf")
                email.content_subtype = "pdf"  # Main content is now text/html
                email.encoding = 'us-ascii'
                email.send()
        

        【讨论】:

        • 按照这个过程,我能够生成一个 pdf,但仍然无法将其作为邮件发送。我有以下错误消息:AssertionError at /forex/1/salary-package/ 没有异常消息未提供异常消息
        【解决方案4】:

        从 Weasysprint 文档中可以看出,调用方法 write_pdf() 将在单个 File 中呈现文档。

        http://weasyprint.readthedocs.io/en/stable/tutorial.html

        一旦你有了一个 HTML 对象,调用它的 write_pdf() 或 write_png() 在单个 PDF 或 PNG 文件中获取呈现文档的方法。

        另外,他们提到了

        没有参数,这些方法在内存中返回一个字节字符串。

        因此,您可以获取其 PDF 字节字符串并将其用于附件或传递文件名以将 PDF 写入。

        有一点你也可以发送一个可写的类文件对象到write_pdf()

        如果你传递一个文件名或一个可写的类文件对象,它们将 直接写在那里。

        您可以像这样生成和附加 PDF 文件:

        pdf = weasyprint.HTML(string=html).write_pdf()
        ...
        email.attach("certificate.pdf", pdf, "application/pdf")
        

        如果成功,您也可以发送 200 响应,如果失败,则发送 500。

        关于 SMTP 服务器的注意事项

        通常您需要一个 SMTP 邮件服务器来将您的邮件中继到您的目的地。

        你可以从 Django 中读到 document send_mail 需要一些 configuration:

        使用 EMAIL_HOST 和 EMAIL_PORT 设置中指定的 SMTP 主机和端口发送邮件。 EMAIL_HOST_USER 和 EMAIL_HOST_PASSWORD 设置(如果设置)用于对 SMTP 服务器进行身份验证,EMAIL_USE_TLS 和 EMAIL_USE_SSL 设置控制是否使用安全连接。

        然后您可以使用 send_mail() 和以下参数将您的消息中继到本地 SMTP 服务器。

        send_mail(主题、消息、from_email、receiver_list、fail_silently=False、auth_user=None、auth_password=None、connection=None、html_message=None)

        注意:不要错过认证参数。

        【讨论】:

        • 嗨@H.Tibat,你能用代码示例指导我吗?
        • 嗨@H.Tibat,现在它正在生成pdf文件但仍未发送电子邮件。
        • 嗨@H.Tibat,我已经设置了所有必需的 SMTP 设置,但send_mail 方法不提供附加文件的方法。要附加文件,我认为我们需要使用EmailMessage 无论如何都不起作用。
        • 嗨@H.Tibat,请看一下更新后的代码!
        猜你喜欢
        • 2011-04-24
        • 2018-10-04
        • 2016-02-13
        • 2013-04-08
        • 1970-01-01
        • 2014-12-10
        • 2019-09-03
        • 1970-01-01
        • 2015-06-21
        相关资源
        最近更新 更多