Search code examples
djangodjango-email

Django email attachment of an uploaded file using modelname.filevariable.url


I have a Django library application, wherein from a list of books, the customer can email a particular book's pdf file link that was originally uploaded using FileField by the admin. Now, the email is being sent/received successfully, however the pdf file is not getting attached.

I have also looked into other Stack Overflow references for the same, but I am unable to interpret the correct solution: Django email attachment of file upload

On clicking the email button, the form is submitted as follows: three hidden values are also being submitted on submitting the form, one of which is the book.file.url.

   <form method="POST" action ="{% url 'email_book' %}" enctype="multipart/form-data">
       {% csrf_token %}

       # correction made
       <input type="hidden" name="book_title" value="{{ book.id }}">

       <button type="submit" class="btn btn-info"><span class="glyphicon glyphicon-envelope"></span>&nbsp;&nbsp;Email</button>
   </form>

In views.py, I have used Django's EmailMessage class as follows:

    def send_email(request):
       # corrections made, pdf file path is being retrieved
       book = Book.objects.get(pk=int(request.POST.get('id')))
       book_title = book.title
       book_author = book.author
       book_pdf = book.file.path  #inplace of book.file.url

      email_body = "PDF attachment below \n Book: "+book_title+"\n Book Author: "+book_author

try:
    email = EmailMessage(
        'Book request',
        email_body,
        'sender smtp gmail' + '<dolphin2016water@gmail.com>',
        ['madhok.simran8@gmail.com'],
    )

    # this is the where the error occurs
    email.attach_file(book_pdf, 'application/pdf')

    email.send()
except smtplib.SMTPException:
    return render(request, 'catalog/index.html')
return render(request, 'catalog/dashboard.html')

The uploaded files are stored in /media/books_pdf/2018/xyz.pdf. And the book.file.url contains the above file path, and yet the pdf file is not getting attached to the email.

So I am retrieving the file path dynamically using book.file.url, and yet the code is right.

How do I retrieve that book's pdf file path/name required.

Update/solution

To retrieve the pdf file path, we have to use book.file.path instead of book.file.url.


Solution

  • The problem is that the attach_file() method expects a filesystem path. You're not passing a path, you're passing the URL.

    You could change your template to output the path into the hidden field - e.g.

    <input type="hidden" name="book_pdf" value="{{ book.file.path }}">
    

    But it might be better to pass the id of the Book, and then from that you can look up all the attributes you need. For example:

    Pass the id of the Book in the template:

       <form method="POST" action ="{% url 'email_book' %}" enctype="multipart/form-data">
           {% csrf_token %}
           <input type="hidden" name="book_id" value="{{ book.id }}">
           <button type="submit" class="btn btn-info"><span class="glyphicon glyphicon-envelope"></span>&nbsp;&nbsp;Email</button>
       </form>
    

    Modify the view to look up the Book from the id:

    def send_email(request):
        book = Book.objects.get(pk=int(request.POST.get('id')))
        book_title = book.title
        book_author = book.author
        book_pdf = book.file.path  # Use the path of the book