【发布时间】: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