I am trying to create a pdf of a template and then have it automatically send an email to the contractor with the created pdf as an attachment.
Emails: I am able to send basic email without any issues
Create PDF: I am able to create the pdf with out any issues.
The issue is trying to combine the two features. I am not sure if I have to have the pdf automatically save to a location on the server and then attach the pdf to an email or if I can create the pdf and then email out in the same code.
def vendorwopdf(request, *args, **kwargs):
wonumb = kwargs.get('WorkOderNumb')
email = None
searchresult = WorkOrders.objects.get(WorkOderNumb=wonumb)
template = get_template("workorders/workorderpdf.html")
html = template.render({"searchresult":searchresult})
result = io.BytesIO()
pdf = pisa.CreatePDF(html, result)
result.seek(0)
result = result.read()
pdf_content = base64.b64encode(result).decode()
email = EmailMessage(
"RE: Authorized Workorder " + wonumb ,
"Greetings please find attached the approved workorder",
"no-reply@example.ca",
["no-reply@example.ca"],
)
email.attach("workorder.pdf", pdf_content, "pdf")
email.send()
return render(request,'workorders/vendorwo.html',{"searchresult":searchresult})
template
{% load static from static %}
<html>
<head>
<meta charset='utf-8'>
<title>Work Order Invoice</title>
<style type="text/css">
th,td{
padding:3px;
}
th{
background-color:white;
color:black;
}
@page {
size: letter portrait;
@frame header_frame{
-pdf-frame-content:header_content;
left:50pt;
width:512pt;
top:15pt;
height:100pt;
}
@frame footer_frame{
-pdf-frame-content:footer_content;
left:50pt;
width:512pt;
top:725pt;
height:100pt;
}
@frame content_frame{
left:50pt;
width:512pt;
top:100pt;
height:580pt;
}
}
</style>
</head>
<body>
<div id="header_content">
<table>
<center><h2> </h2></center>
<tr>
<th align="left"><img src="http://999.999.1.183:8000/static/rclogo.jpg" alt="image" width="250" height="80" /></th>
<th></th>
<th align="left"><p><center><h4>WORKORDER #: {{ searchresult.WorkOderNumb }}<br>DATE CREATED: {{ searchresult.DateCreated }}<br>VENDOR: {{ searchresult.Vendor }} </center></h4>
</th>
<th align="Left">PRIORITY: <u>{{ searchresult.Priority }}</u> <br> </th>
</tr>
</table>
<hr>
</div>
<br>
<div id="content_content">
<div class="container">
<div class="row justify-content-between rounded" style="margin-left:auto; margin-right:auto;"">
<table>
<center><h2> </h2></center>
<tr>
<th align="left">
<h3><u>PROPERTY DETAILS </u> </h3>
<p>{{ searchresult.PropertyName }} <br>
{{ searchresult.CityLocality }}, {{ searchresult.Province }} <br>
{{ searchresult.PostalCode }} </p>
</th>
<th>
</th>
<th align="Left">
<h3><u>CONTACT DETAILS</u> </h3>
<p>{{ searchresult.ContactInfo|safe|linebreaks}} </p>
</th>
</tr>
</table>
</div>
<br>
<hr>
<br>
<div class="row justify-content-between rounded" style="margin-left:auto; margin-right:auto;"">
</div>
<hr>
<div class="row justify-content-between rounded" style="margin-left:auto; margin-right:auto;"">
<div class="col-md-12">
<div class="border bg-light">
<br>
<h4><u>DESCRIPTION OF SERVICE/REPAIRS REQUIRED</u></h4>
<p>{{ searchresult.Description|safe|linebreaks }} </p>
</div>
</div>
</div>
<div class="row justify-content-between rounded" style="margin-left:auto; margin-right:auto;"">
<p><br></p>
</div>
<div class="row justify-content-between rounded" style="margin-left:auto; margin-right:auto;"">
<div class="col-md-12">
<div class="border bg-light">
<h4><u></u></h4>
<h4><u>Terms of Acceptance</u></h4>
{% if searchresult.StudentRental == True %}
{% endif %}
</div>
</div>
</div>
</div>
</body>
</html>
This view will produce the working pdf but I can not attach to email.
def vendorwopdf(request, *args, **kwargs):
wonumb = kwargs.get('WorkOderNumb')
searchresult = WorkOrders.objects.get(WorkOderNumb=wonumb)
template = get_template("workorders/workorderpdf.html")
context = {'searchresult': searchresult}
response = HttpResponse(content_type='application/pdf')
#response['Content-Disposition'] = 'attachment; filename="workorder.pdf"'
response['Content-Disposition'] = 'filename="workorder.pdf"'
template = get_template(template_path)
html = template.render(context)
pisa_status = pisa.CreatePDF(
html, dest=response)
if pisa_status.err:
return HttpResponse('We had some errors <pre>' + html + '</pre>')
return response
You can do something like this to only send the attachment in the mail without saving it in any database.
import io
from django.template.loader import get_template
from xhtml2pdf import pisa
from django.core.mail import EmailMessage
template = get_template("template.html")
html = template.render({"context": context_data})
result = io.BytesIO()
pdf = pisa.CreatePDF(html, result)
result.seek(0)
result = result.read()
pdf_content = base64.b64encode(result).decode()
After that, you can attach the pdf file to your email:
email = EmailMessage(
subject,
body,
from_mail,
to_mail,
cc,
bcc,
)
email.attach("pdf_name", pdf_content, "pdf")
Notice the encoding at last, that is because the pdf content sent in as an attachment should be base64 encoded, or else it'll throw an error.