Django中如何正确发送带PDF附件的邮件?
解决邮件发送与附件异常的问题
嘿,我看了你的代码和遇到的问题,这两个问题其实都是代码里的小细节没处理好,咱们一步步来解决:
第一个问题:收件人没收到邮件,抄送却收到了
问题出在哪?
你在初始化EmailMultiAlternatives的时候,参数传递错了!Django里这个类的cc(抄送)是需要用关键字参数来传递的,你直接把抄送邮箱列表放在了收件人列表后面,这会被当成bcc(密送)参数。另外,你用request.POST.get()来拿表单数据,不如用表单验证后的cleaned_data靠谱——毕竟表单已经通过is_valid()验证了,cleaned_data里的数据是经过校验的,不会有空值或者无效格式。
怎么改?
把收件人和抄送分开,用to=和cc=明确指定,同时换成cleaned_data取数据:
if download_form.is_valid(): ln_go = get_lang_code(request, request.GET.get('lang')) # 换成cleaned_data拿验证后的姓名和邮箱 name = download_form.cleaned_data['name'] email = download_form.cleaned_data['email'] # 这里明确用to和cc关键字参数 msg = EmailMultiAlternatives( 'Het aangevraagde document', f'Geachte {name}, <br/><br />In bijlage sturen wij u het aangevraagde document door. <br /><br />Met vriendelijke groeten, <br /><br /> Het Autralis team', 'no-reply@autralis.com', to=[email], # 收件人 cc=['some-email-address@gmail.com'] # 抄送 )
第二个问题:附件内容错误,显示乱码
问题出在哪?
你给msg.attach()传的是文件路径字符串,但这个方法需要的是文件的二进制内容!所以现在你的附件其实是把"/assets/documents/..."这段文本当成了PDF内容,打开自然是乱码。另外,直接写绝对路径也容易出问题,最好用Django的BASE_DIR来拼接路径,确保不管部署在哪都能找到文件。
怎么改?
先读取PDF的二进制内容,再传给attach():
import os from django.conf import settings # 用BASE_DIR拼接正确的文件路径,适配你的目录结构 file_path = os.path.join(settings.BASE_DIR, 'assets', 'documents', f'case_study{ln_go}.pdf') # 读取文件的二进制数据 with open(file_path, 'rb') as pdf_file: pdf_content = pdf_file.read() # 现在把二进制内容传进去 msg.attach("case_study.pdf", pdf_content, "application/pdf")
完整的修复代码
把上面的修改整合起来,就是这样:
import os from django.conf import settings from django.core.mail import EmailMultiAlternatives if download_form.is_valid(): ln_go = get_lang_code(request, request.GET.get('lang')) # 构建正确的绝对文件路径 file_path = os.path.join(settings.BASE_DIR, 'assets', 'documents', f'case_study{ln_go}.pdf') # 从验证后的表单拿数据 name = download_form.cleaned_data['name'] email = download_form.cleaned_data['email'] # 初始化邮件,参数传递正确 msg = EmailMultiAlternatives( 'Het aangevraagde document', f'Geachte {name}, <br/><br />In bijlage sturen wij u het aangevraagde document door. <br /><br />Met vriendelijke groeten, <br /><br /> Het Autralis team', 'no-reply@autralis.com', to=[email], cc=['some-email-address@gmail.com'] ) msg.content_subtype = "html" # 保持HTML格式 # 读取并附加PDF with open(file_path, 'rb') as pdf_file: pdf_content = pdf_file.read() msg.attach("case_study.pdf", pdf_content, "application/pdf") # 发送邮件,建议加fail_silently=False方便排查错误 msg.send(fail_silently=False)
额外小贴士
- 排查邮件发送失败:如果收件人还是没收到,把
msg.send()改成msg.send(fail_silently=False),这样如果邮件服务器出错会抛出异常,方便你定位问题; - 验证文件存在:可以加一行
assert os.path.exists(file_path), f"找不到PDF文件:{file_path}",提前发现文件路径错误; - HTML邮件优化:硬编码HTML字符串太麻烦,建议用Django模板来渲染邮件内容,以后改文案或者做国际化都方便。
内容的提问来源于stack exchange,提问作者Boky
相关产品推荐
相关产品推荐

