Django邮件自动化发送小体积PDF附件显示0字节问题修复
Django邮件发送PDF附件0字节问题修复
问题表现
- 基于Django开发邮件自动发送功能时,发送的PDF附件文件名可正常显示,但文件大小为0字节,无实际内容无法打开
- 异常存在明确的大小分界特征:发送约3MB的较大PDF文件可正常送达,1~2MB的较小PDF文件发送后必然出现0字节问题
- 调试阶段直接打印上传的
media文件对象,可正常输出对应PDF的文件名
问题根因
核心是文件读取指针的位置处理逻辑错误:
- 代码中为了计算文件大小,执行
media.seek(0, os.SEEK_END)将文件读取指针移动到了文件末尾,调用media.tell()拿到文件大小后,没有将指针重置回文件起始位置 - 后续执行
media.read()读取附件内容时,默认从当前指针位置(也就是文件末尾)开始读取,最终得到空字节流,挂载到邮件里的附件自然是0字节 - 3MB大文件可正常发送,是因为Django默认对大于2.5MB的上传文件采用临时文件存储(
TemporaryUploadedFile),读取时存在隐式的指针重置逻辑,属于偶发正常;1~2MB的小文件走内存存储(InMemoryUploadedFile),无隐式重置逻辑,因此稳定触发空读问题。
修复方案
关键修复步骤:获取完文件大小后,新增一行media.seek(0)将文件指针重置到文件起始位置,再执行附件内容读取
修正后的完整视图代码如下:
import os from django.http import HttpResponse from django.shortcuts import render from django.core.mail import EmailMessage # 此处保留原有项目的模型、表单引入逻辑 # from .forms import BeastForm # from .models import Beast def addbeast(request): if request.method == 'POST': form = BeastForm(request.POST, request.FILES) if form.is_valid(): form.save() name = form.cleaned_data['name'] media = form.cleaned_data['media'] # 获取文件大小 media.seek(0, os.SEEK_END) filesize = media.tell() print(filesize) # 修复:重置文件指针到开头,避免后续读取为空 media.seek(0) subject = "NDA IS Attached" message = "NDA Attachment from " + name sender = "-----@gmail.com" cc_myself = True cc_mail = "----!!!!!!@gmail.com" recipients = ['9999999999@gmail.com'] if cc_myself: recipients.append(cc_mail) try: mail = EmailMessage(subject, message, sender, recipients) mail.attach(media.name, media.read(), media.content_type) mail.send() return HttpResponse("FORM SUBMISSION IS SUCCESSFUL") except Exception as e: # 打印异常信息便于排查问题,不要裸except吞掉所有错误 print(f"Mail send failed: {str(e)}") return HttpResponse('no success') else: form = BeastForm() return render(request, "post_list.html", { "form": form })
额外优化建议
- 禁止使用裸
except捕获所有异常,建议明确捕获异常类型并打印错误日志,避免发送失败时无法定位具体原因 - 如果附件已经保存到服务器本地存储,可直接使用
EmailMessage的attach_file()方法传入文件本地路径读取附件,无需手动处理文件指针,能减少类似问题出现
内容的提问来源于stack exchange,提问作者Heeket Mehta
相关产品推荐
相关产品推荐

