1

I'm trying to send emails with attachments. I'm getting IOError: [Errno 2] No such file or directory. But the URL it says doesn't exist? Well, it actually does exist. The form is uploading the file, and the FileField.url that it produces, with a Signature=...&Expires=...&AWSAccessKeyId= appended to the end, works when I call it up in another window.

My Django app uses Amazon-SES. I was sending them fine with send_mail(), but that wrapper doesn't support attachments, so I switched to this in my tasks.py:

from django.core.mail.message import EmailMessage
from celery import task
import logging
from apps.profiles.models import Client

@task(name='send-email')
def send_published_article(sender, subject, body, attachment):
    recipients = []
    for client in Client.objects.all():
        recipients.append(client.email)
    email = EmailMessage(subject, body, sender, [recipients])
    email.attach_file(attachment)
    email.send()

And I call this in my view on a form.save()

from story.tasks import send_published_article
def add_article(request):
    if request.method == 'POST':
        form = ArticleForm(request.POST, request.FILES or None)
        if form.is_valid():
            article = form.save(commit=False)
            article.author = request.user
            article.save()
            if article.is_published:
                subject = article.title
                body = article.text
                attachment = article.docfile.url
                send_published_article.delay(request.user.email,
                                             subject,
                                             body,
                                             attachment)
            return redirect(article)
    else:
        form = ArticleForm()
    return render_to_response('story/article_form.html', 
                              { 'form': form },
                              context_instance=RequestContext(request))

Here's what the logs say:

app/celeryd.1: File "/app/.heroku/python/lib/python2.7/site-packages/django/core/mail/message.py", line 268, in attach_file 
app/celeryd.1: content = open(path, 'rb').read() 
app/celeryd.1: IOError: [Errno 2] No such file or directory:

Any

Anthony Roberts
  • 1,971
  • 1
  • 19
  • 34

2 Answers2

4

Edit #2 -- The file mode needs to be 'r' if you are going to use the .read() function.

The reason is said "no such file or directory" is because I'd forgotten to use default_storage.open(). The file isn't on the same machine as the app, static files are stored on AWS S3.

from celery import task
from django.core.mail.message import EmailMessage
from django.core.files.storage import default_storage
from apps.account.models import UserProfile

@task(name='send-email')
def send_published_article(sender, subject, body, attachment=None):
    recipients = []
    for profile in UserProfile.objects.all():
        if profile.user_type == 'Client':
            recipients.append(profile.user.email)
    email = EmailMessage(subject, body, sender, recipients)
    try:
        docfile = default_storage.open(attachment.name, 'r')
        if docfile:
            email.attach(docfile.name, docfile.read())
        else:
            pass
    except:
        pass
    email.send()
Anthony Roberts
  • 1,971
  • 1
  • 19
  • 34
0

Attachment has to be a file on your filesystem, search for attach_file in the Django e-mail documentation.

So you can link to the file (URL) in your e-mail or you can download the file, attach it and then delete it locally afterwards.

Simeon Visser
  • 118,920
  • 18
  • 185
  • 180
  • I know how to put the link in the email. I don't know what command I should use to download the file, and delete it afterwards. Any suggestions? I've read [this SO page](http://stackoverflow.com/questions/908258/generating-file-to-download-with-django) and noticed a lot of cStringIO, would that handle this type of task? – Anthony Roberts May 07 '13 at 13:27