17

My app produces pdf reports using django-wkhtmltopdf. I want to be able to attach the pdf to an email and send.

Here is my pdf view:

class Report(DetailView):
    template = 'pdf_reports/report.html'
    model = Model

    def get(self, request, *args, **kwargs):
        self.context['model'] = self.get_object()

        response=PDFTemplateResponse(request=request,
                                     template=self.template,
                                     filename ="report.pdf",
                                     context=self.context,
                                     show_content_in_browser=False,
                                     cmd_options={'margin-top': 0,
                                                  'margin-left': 0,
                                                  'margin-right': 0}
                                     )
        return response

And here is my email view:

def email_view(request, pk):
    model = Model.objects.get(pk=pk)
    email_to = model.email
    send_mail('Subject here', 'Here is the message.', 'from',
    [email_to], fail_silently=False)

    response = HttpResponse(content_type='text/plain')
    return redirect('dashboard')
user3972986
  • 490
  • 1
  • 5
  • 14

3 Answers3

16

The docs say (https://docs.djangoproject.com/en/dev/topics/email/#the-emailmessage-class):

Not all features of the EmailMessage class are available through the send_mail() and related wrapper functions. If you wish to use advanced features, such as BCC’ed recipients, file attachments, or multi-part email, you’ll need to create EmailMessage instances directly.

So you have to create an EmailMessage:

from django.core.mail import EmailMessage

email = EmailMessage(
    'Subject here', 'Here is the message.', 'from@me.com', ['email@to.com'])
email.attach_file('Document.pdf')
email.send()
xbello
  • 7,223
  • 3
  • 28
  • 41
8

If you want to attach a file that is stored in memory you use just attach

msg = EmailMultiAlternatives(mail_subject, text_content, settings.DEFAULT_FROM_EMAIL, [instance.email])
msg.attach_alternative(message, "text/html")
pdf = render_to_pdf('some_invoice.html')
msg.attach('invoice.pdf', pdf)
msg.send()
Islam Murtazaev
  • 1,488
  • 2
  • 17
  • 27
1

One scenario is that the file is kept on disk (for example, in a repository) and accessed via a fixed path. It is safer (and probably easier) to use the field in the model. Assuming that PDF file is stored in a FileField of some model_instance object:

from django.core.mail import EmailMessage

pdf_file = model_instance.file  # <- here I am accessing the file attribute, which is a FileField
message = EmailMessage(
    "Subject",
    "Some body."
    "From@example.com",
    [email_to],
)
message.attach("document.pdf", pdf_file.read())
message.send(fail_silently=False) 
rafaljusiak
  • 1,050
  • 1
  • 10
  • 17
  • Instead of 'message.attach("document.pdf", pdf_file.read())' you can take your instance of PDFTemplateResponse (let's call the instance variable "res") and use 'message.attach("document.pdf", res.rendered_content)'. Then you can use the generated PDF without saving it to the filesystem first. – loafer Feb 24 '22 at 14:40