【问题标题】:.zip file gets corrupted when sent with gmail api and compressed with zlib.zip 文件在使用 gmail api 发送并使用 zlib 压缩时损坏
【发布时间】:2020-02-22 00:00:49
【问题描述】:

我正在使用 Python 3.7 并使用 Python 的 zipfilezlib 压缩 .csv 文件。

import zipfile

filename = "report.csv"

zip_filename = f"{filename[:-4]}.zip"
with zipfile.ZipFile(zip_filename, "w", compression=zipfile.ZIP_DEFLATED) as zip:
    zip.write(filename)

然后将 zip 文件附加到电子邮件中,我有一些逻辑来确定它的 MIME 类型(我已经检查它是否正确地确定它是 application/zip):

def _make_attachment_part(self, filename: str) -> MIMEBase:
    content_type, encoding = mimetypes.guess_type(filename)
    if content_type is None or encoding is not None:
        content_type = "application/octet-stream"

    main_type, sub_type = content_type.split("/", 1)
    msg = MIMEBase(main_type, sub_type)
    with open(filename, "rb") as f:
        msg.set_payload(f.read())

    base_filename = os.path.basename(filename)
    msg.add_header("Content-Disposition", "attachment", filename=base_filename)

    return msg

然后,为message 设置主题、收件人、抄送、附件等,该MIMEMultipart 类型。然后,我使用base64 进行编码并发送它。

raw_message = base64.urlsafe_b64encode(message.as_bytes()).decode()

我收到了正确命名且大小符合预期的附件,但是,当我尝试使用 unzip file.zip 时,我收到以下错误:

error [file.zip]:  missing 5 bytes in zipfile

有人知道我做错了什么吗?事实上,电子邮件是从 Ubuntu 机器发送的,而我试图在 MacOS 上打开收到的文件。

【问题讨论】:

    标签: python gmail-api mime-types zlib mime


    【解决方案1】:

    rfc1341中所定义:

    7BIT 的编码类型要求正文已经是 7 位邮件就绪表示。这是默认值——也就是说,如果 Content-Transfer-Encoding 标头字段不存在,则假定为“Content-Transfer-Encoding: 7BIT”。

    在您的情况下,在 _make_attachment_part 函数中,您将有效负载设置为您的 MIMEBase 对象,但您没有指定 Content-Transfer-Encoding。

    我建议您将有效负载编码为 Base64。你可以这样做:

    1. 导入encoders 模块
    from email import encoders
    
    1. 在您的 _make_attachment_part 函数中,使用 encoders 模块对您的有效负载进行编码。
    def _make_attachment_part(self, filename: str) -> MIMEBase:
        content_type, encoding = mimetypes.guess_type(filename)
        if content_type is None or encoding is not None:
            content_type = "application/octet-stream"
    
        main_type, sub_type = content_type.split("/", 1)
        msg = MIMEBase(main_type, sub_type)
        with open(filename, "rb") as f:
            msg.set_payload(f.read())
    
        encoders.encode_base64(msg) # NEW
    
        base_filename = os.path.basename(filename)
        msg.add_header("Content-Disposition", "attachment", filename=base_filename)
    
        return msg
    

    【讨论】:

    • 非常感谢您的回答!这确实解决了问题!
    猜你喜欢
    • 2021-10-08
    • 2012-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多