Home > Software design >  Django mail attachments blank except for 1st email sent, when looping through recipients
Django mail attachments blank except for 1st email sent, when looping through recipients

Time:10-21

I have a newsletter being sent out using Django forms, with multiple files that can be attached.
I'm looping through the list of recipients (if they are verified, and agreed to receive the newsletter, etc.)
It all works fine, emails are received to these users, including 1 or more attached files.

The problem is only the first user gets file\s with content, others get the file/s, but they are empty/blank (Zero bytes).
Is it linked to some temp files or the need to cache these files first? so they're available for the loop to handle?
(note: the file name, number of files, etc. received to all recipients is all correct - they are just empty, except the first email)

How can I resolve that? Thanks

forms.py

class NewsletterForm(forms.Form):
    message = forms.CharField(widget = forms.Textarea, max_length = 8000)
    attach = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}), required=False)

views.py

def newsletter(request):
    users = User.objects.all()
    receipient_list = []
    for user in users:
        if user.profile.newsletter_agree == True and user.profile.verified_member == True:
            receipient_list.append(user.email)

    if request.method == 'POST':
        form = NewsletterForm(request.POST, request.FILES)
        if form.is_valid():
            mail_subject = 'Some newsletter subject'
            message = form.cleaned_data['message'], 
            files = request.FILES.getlist('attach')

            for contact_name in receipient_list:
                try:
                 email = EmailMessage(mail_subject, message, '[email protected]', to=[contact_name])
                 email.encoding = 'utf-8'
                 for f in files:
                    email.attach(f.name, f.read(), f.content_type)
                 email.send()
                 except BadHeaderError:
                    return HttpResponse('Invalid header found.')

            messages.success(request, f'Newsletter sent successfully')
            return redirect('main_page')
    
    form = NewsletterForm()
        
    context = {'form':form}

    return render(request, 'my_app/newsletter.html', context)

newsletter.html

<form method="POST" enctype="multipart/form-data">
    <fieldset > 
        {% csrf_token %}
        {{ form|crispy }}
    </fieldset>
    <div >
        <button >Send</button>
    </div>
</form>

CodePudding user response:

The file read function: f.read() reads through the file and returns it as a string but leaves the read cursor at the end of the file. So when you call it a second time it returns nothing.

Some options might be to use attach_file instead of attach:

email.attach_file(f.name, f.content_type)

or reading each file once, creating a list of attachment triples and re-using the list.

files = request.FILES.getlist('attach')
attachments = []
for f in files:
    attachments.append((f.name, f.read(), f.content_type))

for contact_name in receipient_list:
   try:
       email = EmailMessage(mail_subject, message, '[email protected]', to=[contact_name], attachments=attachments)
       email.encoding = 'utf-8'
       email.send()
  • Related