Python用BytesIO+MIMEApplication从S3发图片邮件附件为0字节问题
问题描述
我使用如下代码从S3存储桶下载文件,通过BytesIO将读取的数据存入内存而非本地文件:
with io.BytesIO() as img: img.name = 'screenshot.png' try: get_bucket().download_fileobj(key, img) except Exception as e: logger.error('ERROR processing screenshot, exception: %s', str(e)) raise NotFoundError()
随后通过以下代码发送邮件:
part = MIMEApplication(attachment.read()) part.add_header('Content-Disposition', 'attachment', filename=os.path.basename(attachment.name)) msg.attach(part) _ses.send_raw_email(Source=sender, Destinations=recipients, RawMessage={'Data': msg.as_string()})
其中attachment为上述img(BytesIO)对象。但收到邮件时,附件字节数为0或无法正常显示。应用使用的是旧版本boto3 1.13.13,当前仅进行维护工作。请问该问题的可能原因是什么?
可能的原因
- BytesIO指针位置未重置:调用
download_fileobj写入数据后,BytesIO的文件指针会停留在数据末尾,此时直接调用read()会读取到空内容。需要在读取前执行attachment.seek(0)将指针移到起始位置。 - 旧版boto3的潜在bug:boto3 1.13.13是2020年的旧版本,
download_fileobj在处理BytesIO时可能存在兼容性问题,比如未能完整写入数据,或者写入后指针状态异常。可以在写入后通过img.tell()检查是否有数据写入(返回值为0则说明未写入任何内容),同时确认S3桶中的目标文件本身不为空。 - MIME类型处理不当:如果附件是PNG图片,直接使用
MIMEApplication通用类型可能不如指定具体MIME类型可靠,旧版email库可能对通用类型的解析存在问题。可以替换为MIMEImage(attachment.read()),或者在MIMEApplication中指定_subtype='png'参数。 - 上下文管理器作用域问题:
img是在with语句块内创建的,当代码退出with块时,BytesIO对象会被自动关闭。如果后续在with块外使用attachment(即已关闭的对象)读取内容,会导致读取失败,附件为空。需要确保邮件附件的处理逻辑在with块内完成,或者将BytesIO中的数据复制到另一个持久化的BytesIO对象中。
内容的提问来源于stack exchange,提问作者user2300947
相关产品推荐
相关产品推荐

