Django循环发送邮件仅首封附件有内容,其余为空如何解决?
解决Django多附件邮件仅第一个收件人收到有效附件的问题
问题原因
核心问题出在文件对象的指针位置:第一次调用f.read()读取附件内容后,文件指针会移动到文件末尾,后续再次调用f.read()时会直接返回空字节,导致后续收件人的附件内容为空。
修复方案
方案1:每次读取前重置文件指针到开头
在每次循环发送邮件前,将文件指针重置到起始位置(seek(0)),确保每次读取都能获取完整的文件内容。
修改views.py中的循环部分:
def newsletter(request): users = User.objects.all() receipient_list = [] for user in users: if user.profile.newsletter_agree and user.profile.verified_member: 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变成元组 message = form.cleaned_data['message'] files = request.FILES.getlist('attach') for contact_name in receipient_list: try: email = EmailMessage(mail_subject, message, 'email@email.com', to=[contact_name]) email.encoding = 'utf-8' for f in files: # 重置文件指针到开头 f.seek(0) 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)
方案2:提前将所有附件内容读入内存
如果附件体积不大,可以提前把所有文件的名称、内容、类型存储在内存列表中,后续循环直接使用内存数据,避免重复操作文件对象。
修改views.py:
def newsletter(request): users = User.objects.all() receipient_list = [] for user in users: if user.profile.newsletter_agree and user.profile.verified_member: 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'] # 提前读取所有附件内容到内存 attachments = [] for f in request.FILES.getlist('attach'): attachments.append({ 'name': f.name, 'content': f.read(), 'content_type': f.content_type }) for contact_name in receipient_list: try: email = EmailMessage(mail_subject, message, 'email@email.com', to=[contact_name]) email.encoding = 'utf-8' for att in attachments: email.attach(att['name'], att['content'], att['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)
额外注意点
- 原代码中
message = form.cleaned_data['message'],末尾多了一个逗号,会导致message变成元组类型,可能引发邮件内容显示异常,修复代码中已移除。 - 大附件建议用方案1,避免占用过多内存;小附件用方案2更高效。
内容的提问来源于stack exchange,提问作者Jonasz
相关产品推荐
相关产品推荐

