ZIP-файл поврежден при отправке через gmail api и сжат с помощью zlib - PullRequest
2 голосов
/ 25 октября 2019

Я использую Python 3.7 и сжимаю файл .csv, используя zipfile и zlib в Python.

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.

1 Ответ

1 голос
/ 28 октября 2019

Как определено в rfc1341 :

Тип кодирования 7BIT требует, чтобы тело уже было в семибитном представлении, готовом к отправке. Это значение по умолчанию, то есть «Content-Transfer-Encoding: 7BIT» предполагается, если поле заголовка Content-Transfer-Encoding отсутствует.

В вашем случае, в *Функция 1009 *, вы устанавливаете полезную нагрузку для своего MIMEBase объекта, но не указываете Content-Transfer-Encoding.

Я предлагаю вам кодировать свою полезную нагрузку как Base64. Вы можете сделать это следующим образом:

  1. Импортировать модуль encoders
from email import encoders
Внутри вашей функции _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
...