Reputation: 5684
I'm trying to generate a pdf file from an HTML template using Weasyprint python package and I need to send it via email using.
Here's what i have tried:
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')
But it returns an error as
TypeError: expected bytes-like object, not HttpResponse
How can I generate and send a pdf file to an email from HTML template?
Update: With this updated code now it's generating pdf and sending an email but when I open attached pdf file from recieved email it says
unsupported file formate data
.
Here's the updated Code:
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 = '[email protected]'
to_emails = ['[email protected]', '[email protected]']
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')
Help me, please!
Thanks in advance!
Upvotes: 4
Views: 11367
Reputation: 2418
Building on @Rishabh gupta answer:
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=("[email protected]",),
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
Upvotes: 0
Reputation: 87
This code works for me
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 = ['[email protected]']
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)
Upvotes: 1
Reputation: 5684
Here's the complete working version of above code:
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()
Upvotes: 5
Reputation: 373
As you can see from Weasysprint document, calling method write_pdf()
will render the document in a single File
.
http://weasyprint.readthedocs.io/en/stable/tutorial.html
Once you have a HTML object, call its write_pdf() or write_png() method to get the rendered document in a single PDF or PNG file.
Also, they mention that
Without arguments, these methods return a byte string in memory.
So, you can get its PDF byte string and use it for attachment or pass the filename to write the PDF to.
There is a point that you can also send a writable file-like object to write_pdf()
.
If you pass a file name or a writable file-like object, they will write there directly instead.
You can generate and attach the PDF file like this:
pdf = weasyprint.HTML(string=html).write_pdf()
...
email.attach("certificate.pdf", pdf, "application/pdf")
You can also send 200 Response if it was successful or 500 if it failed.
NOTE About SMTP Server
Normally you need an SMTP mail server for relaying your message to your destination.
As you can read from Django document send_mail
need some configuration:
Mail is sent using the SMTP host and port specified in the EMAIL_HOST and EMAIL_PORT settings. The EMAIL_HOST_USER and EMAIL_HOST_PASSWORD settings, if set, are used to authenticate to the SMTP server, and the EMAIL_USE_TLS and EMAIL_USE_SSL settings control whether a secure connection is used.
Then you can use send_mail()
with following parameters for relaying your message to the local SMTP server.
send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=None, auth_password=None, connection=None, html_message=None)
Attention: Don't miss authentication parameters.
Upvotes: 3