![](/img/trans.png)
[英]OSError: Errno 30 Read-only file system: Any way to create a CSV and attach it to email from Python in AWS Lambda?
[英]How can I attach a file from an HTTP request to an email? (Python/ AWS Lambda)
我目前正在嘗試將電子郵件發送微服務遷移到雲中。 我的代碼在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
設法自己得到它。 我懷疑這是一個編碼問題。 發送附件文件之前,先在Base64中對其進行編碼,然后在Lambda中對其進行解碼就可以了。 似乎在將附件文件發送到Lambda之前未正確讀取附件文件,這導致了問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.