0

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.

halfer
  • 19,824
  • 17
  • 99
  • 186
Simran
  • 593
  • 1
  • 14
  • 37
  • Have you tried passing an explicit mime type - e.g. `email.attach_file(book_pdf, mimetype='application/pdf')`? – Will Keeling Dec 10 '18 at 11:40
  • yes i have tried this, the error still persists: No such file or directory: '/media/books_pdf/2018/xyz.pdf for whichever specific i made the email request – Simran Dec 10 '18 at 12:53

1 Answers1

1

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
Will Keeling
  • 22,055
  • 4
  • 51
  • 61
  • and yes it is a better practice to retrieve that book through its PK in the view, and then accessing its fields – Simran Dec 10 '18 at 13:15