我正试图让AWS SES Lambda forwarder Python sample code不经修改地将电子邮件转发到外部帐户。在下面的(A)中,除非电子邮件是多部分的,否则邮件正文将无法正确转发。大多数错误与以下因素有关:
body = MIMEText(str(mailobject.get_payload(decode=True), 'UTF-8'))
如果我正确理解python文档,当MIMEmultipart为false时,它应该将电子邮件正文作为字符串传递给body。根据该行代码的执行方式,它将发送如下所示的正文,或者编译器将返回如(B)所示的错误,或者“str”对象没有属性“policy”“
当我收到一封电子邮件时,它是什么样子的。html格式显示为文本
<html>
<body>
<p>You have chosen to subscribe to the topic:
<br /><b>arn:aws:sns:I INTENTIONALLY REMOVED THIS</b></p>
<p>To confirm this subscription, click or visit the link below (If this was in error no action is necessary):
<br /><a href="https://sns.us-east-1.amazonaws.com/confirmation.html?TopicArn=arn:aws:sns:us-east-1:I INTENTIONALLY REMOVED THIS</a></p>
<p><small>Please do not reply directly to this email. If you wish to remove yourself from receiving all future SNS subscription confirmation requests please send an email to <a href="mailto:sns-opt-out@amazon.com">sns-opt-out</a></small></p>
</body>
</html>
(A)我使用的代码:
import os
import boto3
import email
import re
from botocore.exceptions import ClientError
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from datetime import datetime
region = os.environ['Region']
def get_time():
# datetime object containing current date and time
now = datetime.now()
# dd/mm/YY H:M:S
return now.strftime("%d/%m/%Y %H:%M:%S")
def get_message_from_s3(message_id):
incoming_email_bucket = os.environ['MailS3Bucket']
incoming_email_prefix = os.environ['MailS3Prefix']
if incoming_email_prefix:
object_path = (incoming_email_prefix + "/" + message_id)
else:
object_path = message_id
object_http_path = (f"http://s3.console.aws.amazon.com/s3/object/{incoming_email_bucket}/{object_path}?region={region}")
# Create a new S3 client.
client_s3 = boto3.client("s3")
# Get the email object from the S3 bucket.
object_s3 = client_s3.get_object(Bucket=incoming_email_bucket,
Key=object_path)
# Read the content of the message.
file = object_s3['Body'].read()
file_dict = {
"file": file,
"path": object_http_path
}
return file_dict
def create_message(file_dict):
stringMsg = file_dict['file'].decode('utf-8')
# Create a MIME container.
msg = MIMEMultipart('alternative')
sender = os.environ['MailSender']
recipient = os.environ['MailRecipient']
# Parse the email body.
mailobject = email.message_from_string(file_dict['file'].decode('utf-8'))
#print(mailobject.as_string())
# Get original sender for reply-to
from_original = mailobject['Return-Path']
from_original = from_original.replace('<', '');
from_original = from_original.replace('>', '');
print(from_original)
# Create a new subject line.
subject = mailobject['Subject']
body = ""
if mailobject.is_multipart():
print('IS multipart')
index = stringMsg.find('Content-Type: multipart/')
stringBody = stringMsg[index:]
#print(stringBody)
stringData = 'Subject: ' + subject + '\nTo: ' + sender + '\nreply-to: ' + from_original + '\n' + stringBody
message = {
"Source": sender,
"Destinations": recipient,
"Data": stringData
}
return message
for part in mailobject.walk():
ctype = part.get_content_type()
cdispo = str(part.get('Content-Disposition'))
# case for each common content type
if ctype == 'text/plain' and 'attachment' not in cdispo:
bodyPart = MIMEText(part.get_payload(decode=True), 'plain', part.get_content_charset())
msg.attach(bodyPart)
if ctype == 'text/html' and 'attachment' not in cdispo:
mt = MIMEText(part.get_payload(decode=True), 'html', part.get_content_charset())
email.encoders.encode_quopri(mt)
del mt['Content-Transfer-Encoding']
mt.add_header('Content-Transfer-Encoding', 'quoted-printable')
msg.attach(mt)
if 'attachment' in cdispo and 'image' in ctype:
mi = MIMEImage(part.get_payload(decode=True), ctype.replace('image/', ''))
del mi['Content-Type']
del mi['Content-Disposition']
mi.add_header('Content-Type', ctype)
mi.add_header('Content-Disposition', cdispo)
msg.attach(mi)
if 'attachment' in cdispo and 'application' in ctype:
ma = MIMEApplication(part.get_payload(decode=True), ctype.replace('application/', ''))
del ma['Content-Type']
del ma['Content-Disposition']
ma.add_header('Content-Type', ctype)
ma.add_header('Content-Disposition', cdispo)
msg.attach(ma)
# not multipart - i.e. plain text, no attachments, keeping fingers crossed
else:
body = MIMEText(str(mailobject.get_payload(decode=True), 'UTF-8'))
msg.attach(body)
# The file name to use for the attached message. Uses regex to remove all
# non-alphanumeric characters, and appends a file extension.
filename = re.sub('[^0-9a-zA-Z]+', '_', subject)
# Add subject, from and to lines.
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = recipient
msg['reply-to'] = mailobject['Return-Path']
# Create a new MIME object.
att = MIMEApplication(file_dict["file"], filename)
att.add_header("Content-Disposition", 'attachment', filename=filename)
# Attach the file object to the message.
msg.attach(att)
message = {
"Source": sender,
"Destinations": recipient,
"Data": msg.as_string()
}
return message
def send_email(message):
aws_region = os.environ['Region']
# Create a new SES client.
client_ses = boto3.client('ses', region)
# Send the email.
try:
#Provide the contents of the email.
response = client_ses.send_raw_email(
Source=message['Source'],
Destinations=[
message['Destinations']
],
RawMessage={
'Data':message['Data']
}
)
# Display an error if something goes wrong.
except ClientError as e:
output = e.response['Error']['Message']
else:
output = "Email sent! Message ID: " + response['MessageId']
return output
def lambda_handler(event, context):
# Get the unique ID of the message. This corresponds to the name of the file
# in S3.
message_id = event['Records'][0]['ses']['mail']['messageId']
print(f"Received message ID {message_id}")
# Retrieve the file from the S3 bucket.
file_dict = get_message_from_s3(message_id)
# Create the message.
message = create_message(file_dict)
#this alone didn't fix it: message = create_message(str(file_dict))
# Send the email and print the result.
result = send_email(message)
print(result)
(B)this post中的代码示例在“body”赋值和我一直试图在(A)中得到的工作中失败了
body = MIMEText(mailobject.get_payload(decode=True), 'UTF-8')
msg.attach(body)
Response:
{
"errorMessage": "'bytes' object has no attribute 'encode'",
"errorType": "AttributeError",
"stackTrace": [
" File \"/var/task/lambda_function.py\", line 190, in lambda_handler\n message = create_message(file_dict)\n",
" File \"/var/task/lambda_function.py\", line 128, in create_message\n body = MIMEText(mailobject.get_payload(decode=True), 'UTF-8')\n",
" File \"/var/lang/lib/python3.8/email/mime/text.py\", line 34, in __init__\n _text.encode('us-ascii')\n"
]
}
若要复制此问题,请启动一个新的SES实例,按照original AWS SES Lambda forwarder Python sample code的教程进行操作并验证其是否有效。然后,将AWS示例代码替换为(a)中的my代码或其他链接示例之一
另外,I found this Lambda email test event code并且能够让它足够工作,以便从AWS Lambda仪表板测试此代码。为了使其工作,我在仪表板中创建了两个新的测试事件(多部分/非多部分),并粘贴在该代码中,更改(a)电子邮件地址(如适用),(b)Lambda函数ARN到我函数的ARN,以及(c)存储在我的活动s3实例上的适用电子邮件的消息id。这为我省去了手动创建和发送测试电子邮件以进行调试的麻烦,希望其他找到此帖子并有类似问题的人也能这样做。该测试代码将导致转发实际电子邮件
目前没有回答
相关问题 更多 >
编程相关推荐