【问题标题】:How can I attach a file from an HTTP request to an email? (Python/ AWS Lambda)如何将来自 HTTP 请求的文件附加到电子邮件? (Python/AWS Lambda)
【发布时间】:2019-12-08 04:49:56
【问题描述】:

我目前正在尝试将电子邮件发送微服务迁移到云端。我的代码位于 AWS Lambda 函数中,该函数由发送到终端节点的 http 请求触发。如果该 HTTP 请求包含文件附件,我的代码应将该文件附加到它发送的电子邮件中。

目前,我的代码可以正常发送电子邮件,但是当我尝试发送附件时,它会出现乱码。在以 HTTP 请求发送文件然后将其附加到电子邮件的过程中,文件的内容会在某处发生更改。但是,可以毫无问题地发送 .txt 文件。为什么会这样搞砸文件?

提前感谢您的帮助。

我怀疑编码有问题,所以我尝试(如下所示)发送附件的二进制数据,以二进制形式读取该数据,然后编写一个包含该二进制文件的附件对象,但它没有帮助。 我还尝试更改将文件附加到 HTTP 请求的方式,以防它的读取方式存在问题,但没有任何更改。此外,我尝试上传到 s3 存储桶而不是附加到电子邮件,但这也没有改变任何东西。

这是发送 HTTP 请求的代码:

import requests
import json
import os

url = "..."

payload = {
    "requester": "Our robotic overlords",
    "recipients": [
        "..."
    ],
    "message": "This is the message the recipient will see",
    "subject": "THIS IS A SAMPLE. DO NOT BE ALARMED"
}

headers = {
    'content-type': "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
    'Accept': "application/json",
    'Cache-Control': "no-cache",
    'Postman-Token': "79f6f992-0b1b-45a4-a00e-f095be17dc56,ce0c120c-b3f6-4658-89cd-269b122f0342",
    'Host': "q4kisdfuog.execute-api.us-east-1.amazonaws.com",
    'Accept-Encoding': "gzip, deflate",
    'Connection': "keep-alive",
    'cache-control': "no-cache"
    }

toupload = open("VPC.png", "rb")

files = { 
    "file" : ("VPC.png", toupload.read(), "application/octet-stream"),
    "json" : (None, json.dumps(payload), "application/json")
}

response = requests.request("POST", url,  headers=headers, files=files)

print(response.text)

这是托管在我的 Lambda 函数中的代码,它接收 HTTP 请求,并根据它发送一封电子邮件(带有附件):

    # get the system time when the request is received.
    time_received = datetime.now()

    # Get the incoming request body
    en = EmailNotification("n/a", "n/a", "n/a", time_received)

    try:

        req_body = request["body"]
        first_new_line = req_body.find("\r\n")
        req_boundary = req_body[:first_new_line]
        print(req_boundary)

        req_body_parts = req_body.split(req_boundary)

        message_body = req_body_parts[len(req_body_parts)-2]
        body_start = message_body.find("{")
        message_body = message_body[body_start:]
        file_data = req_body_parts[1]

        # process the request's main body to a EmailNotification object
        req_json = json.loads(message_body)
        requester = req_json["requester"]
        recipients = req_json["recipients"]
        subject = req_json["subject"]
        message = req_json["message"]

        en.set_requester(requester)
        en.set_recipients(recipients)
        en.set_subject(subject)
        en.set_message(message)

        print("Message Good")

        file_data_parts = file_data.split("\r\n")

        file_name_start = file_data_parts[1].find("filename=") + 10
        file_name = file_data_parts[1][file_name_start : len(file_data_parts[1]) - 1]
        print(file_name)

        # add the basic info of the attached file to the EmailNotification object
        filesize = -1
        filetype_start = file_data_parts[2].find("Content-Type: ") + 14
        filetype = file_data_parts[2][filetype_start : len(file_data_parts[2])]
        print(filetype)

        attach_obj = Attachment(file_name, filetype, filesize)
        en.set_attachment(attach_obj)

        print("creates attachment")

        # Prepare the email to send 
        msg = MIMEMultipart()
        msg['From'] = EmailNotification.SERVER_EMAIL_ACCOUNT
        msg['To'] = ','.join(en.get_recipients())
        msg['Subject'] = en.get_subject()

        # prepare the main message part of the email
        main_msg = MIMEText(en.get_message(),'plain')

        print("Creates message")

        # prepare the attachment part of the email
        content_type = filetype
        main_type = content_type.split("/")[0]
        sub_type = content_type.split("/")[1]

        binary_parts = []

        for part in file_data_parts[4:]:
            binary_parts.append(BytesIO((part.join("\r\n")).encode("utf-8")))

        print("reads contents")

        path = "/tmp/" + file_name
        target_file = open(path, "wb+")

        for item in binary_parts:
            target_file.write(item.read())

        target_file.close()
        print("WRITES")

        toupload = open(path, "rb")

        att_part = MIMEBase(main_type,sub_type)
        att_part.set_payload(toupload.read())
        encoders.encode_base64(att_part)
        att_part.add_header('Content-Disposition','attachment; filename={}'.format(file_name))

        toupload.close()

        print("ACTUALLY CREATES ATTACHMENT")

        # attach each sub part to the email message
        msg.attach(main_msg)
        msg.attach(att_part)

        print("ATTACHES PARTS TO MESSAGE")

        # Send the email according to SMTP protocol
        try:
            with smtplib.SMTP(SERVER, PORT) as server:
                print(server.ehlo())
                print(server.sendmail(SERVER_EMAIL_ACCOUNT, ','.join(en.get_recipients()), msg.as_string()))','.join(en.get_recipients()), msg.as_string()))
        except Exception as ex:
            print("FAILS IN EMAIL SENDING")
            en.log()
            response = prep_response(en)
            return response
        else:
            print("SUCCEEDS")
            los = []
            for i in range(len(en.get_recipients())):
                los.append(Status.SUCCESS)
            en.set_status(los)
            en.log()
            response = prep_response(en)
            # Send a HTTP response to the client
            return response

    except Exception as ex:

        print("FAILS! w/")
        print(ex)

        # catch exception during parsing the request received
        los = []
        for i in range(len(en.get_recipients())):
            los.append(Status.REQUEST_BODY_ERROR)
        en.set_status(los)
        en.log()
        response = prep_response(en)
        return response

此代码返回的附件具有正确的名称和文件类型,但无法打开,并且与原始文件相比具有不同的内容。例如,如果我附加 VPC.png (56kb),我会返回 VPC.png (99kb)。

如果我查看文件的实际内容,原始文件看起来像这样(只是一个示例):

‰PNG

IHDR é ì ^)¸ sRGB

附加版本如下所示(只是一个示例):

�PNG

IHDR��^).sRGB

【问题讨论】:

    标签: python-3.x email encoding aws-lambda python-requests


    【解决方案1】:

    设法自己得到它。正如我所怀疑的,这是一个编码问题。在发送之前在 Base64 中编码附件文件,然后在 Lambda 中对其进行解码就可以了。附件文件在发送到 Lambda 之前似乎没有被正确读取,这导致了问题。

    【讨论】:

      猜你喜欢
      • 2021-03-17
      • 1970-01-01
      • 1970-01-01
      • 2014-06-25
      • 2021-07-22
      • 2019-12-07
      • 1970-01-01
      • 2017-11-07
      • 1970-01-01
      相关资源
      最近更新 更多