Django中使用smtplib发送多附件邮件仅最后一个附件可正常打开
问题分析与解决
你的问题核心在于MIME类型参数设置错误,以及文件读取逻辑的小问题,导致邮件客户端无法正确解析除最后一个外的所有附件:
- 你直接将完整的
attachment.content_type作为MIMEBase的子类型参数传入,而MIMEBase需要拆分后的主类型(如application、image)和子类型(如pdf、png),错误的MIME格式会让客户端识别附件为损坏状态。 - 直接操作
attachment.file底层文件对象不如使用Django封装的UploadedFile.read()可靠,后者会自动处理文件指针位置。
修复后的原生SMTP代码
attachments = request.FILES msg = MIMEMultipart() msg['Subject'] = subject msg['From'] = EMAIL_ADDRESS msg['To'] = ', '.join(recipients) msg.attach(MIMEText(body, "html")) attachment_list = attachments.getlist('attachment') if attachment_list: for attachment in attachment_list: # 拆分MIME类型为主、子类型 main_type, sub_type = attachment.content_type.split('/') payload = MIMEBase(main_type, sub_type) # 使用UploadedFile自带的read()方法,自动处理文件指针 file_content = attachment.read() payload.set_payload(file_content) encoders.encode_base64(payload) # 编码文件名避免乱码 payload.add_header( 'content-disposition', 'attachment', filename=('utf-8', '', attachment.name) ) msg.attach(payload) smtp_server = smtplib.SMTP_SSL('smtp.gmail.com', 465) smtp_server.login(EMAIL_ADDRESS, PASSWORD) smtp_server.sendmail(EMAIL_ADDRESS, recipients, msg.as_string()) smtp_server.quit()
更简洁的Django原生实现
用Django自带的EmailMultiAlternatives可以省去手动处理MIME类型的麻烦,代码更简洁可靠:
from django.core.mail import EmailMultiAlternatives attachment_list = request.FILES.getlist('attachment') msg = EmailMultiAlternatives( subject=subject, body=body, from_email=EMAIL_ADDRESS, to=recipients ) # 添加HTML格式的邮件内容 msg.attach_alternative(body, "text/html") # 批量添加附件 for attachment in attachment_list: msg.attach(attachment.name, attachment.read(), attachment.content_type) msg.send()
关键修正说明
- 拆分MIME类型:确保
MIMEBase的参数符合标准格式,让邮件客户端能正确识别附件类型。 - 使用UploadedFile的read():Django封装的方法会自动处理文件指针,避免重复读取时的空内容问题。
- 文件名编码:通过
('utf-8', '', attachment.name)格式编码文件名,解决中文或特殊字符文件名乱码问题。
内容的提问来源于stack exchange,提问作者dave32402
相关产品推荐
相关产品推荐

