Reputation: 304
I'm running a simple function on AWS Lambda that sends emails via SMTP.
The function uses various parameters from event
such as "event["reply_to_msg_id"]
" and "event["sender_name"]
".
import smtplib
from email.message import EmailMessage
from email.utils import make_msgid
def lambda_handler(event, context):
msg = EmailMessage()
if event["reply_to_msg_id"] != "":
msg['References'] = event["reply_to_msg_id"]
msg['In-Reply-To'] = event["reply_to_msg_id"]
msg['subject'] = "Re: " + event["content"]["Subject Line"]
else:
msg['subject'] = event["content"]["Subject Line"]
msg['from'] = event["sender_name"]
msg['To'] = event["target_email"]
msg['Message-ID'] = make_msgid('random_client_id')
msg.add_header('Content-Type', 'text/html')
msg.set_payload(event["content"]["Body"])
server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
result = {"Message-ID": msg['Message-ID']}
try:
server.login(event["email_account"]["email_address"], event["email_account"]["password"])
server.send_message(msg)
server.quit()
result["Status"] = "Success"
except Exception as E:
result["Status"] = str(E)
return {
'statusCode': 200,
'headers': {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
'body': json.dumps(result),
"isBase64Encoded": False
}
When I run a Test event in AWS Lambda with the following body, everything works perfectly:
{
"reply_to_msg_id": "",
"content": {
"Subject Line": "Test subject line.",
"Body": "This is <b>a body</b>."
},
"sender_name": "Joe Peschi",
"target_email": "[email protected]",
"email_account": {
"email_address": "***********",
"password": "***********"
}
}
The Problem:
I can't figure out how to actually reproduce this using the API Gateway. I created an API Gateway trigger for this function, but no matter what I try - I'm not able to properly pass the above parameters into Events like when I run the Lambda test.
Upvotes: 0
Views: 1855
Reputation: 304
Took me hours of messing about, but I figured it out.
json_body = json.loads(json.loads(json.dumps(event, default=str))["body"])
Using the line above, I'm able to send this JSON body and turn it into a dict variable:
{
"reply_to_msg_id": "",
"content": {
"Subject Line": "Test subject line.",
"Body": "This is <b>a body</b>."
},
"sender_name": "Joe Peschi",
"target_email": "[email protected]",
"email_account": {
"email_address": "***********",
"password": "***********"
}
}
However, I also wanted to continue using event
, so that I can continue running tests in Lambda with the original JSON structure.
So I created this code:
# THIS LINE TAKES THE REQUEST'S JSON BODY, AND TURNS IT INTO A DICT:
try:
json_body = json.loads(json.loads(json.dumps(event, default=str))["body"])
except:
json_body = ""
if json_body != "":
event = json_body
Now I can run a cURL request and it will work perfectly:
curl --location --request GET 'https://********.execute-api.us-east-2.amazonaws.com/default/send_email_via_smtp' \
--header 'x-api-key: ****************' \
--header 'Content-Type: text/plain' \
--data-raw '{
"reply_to_msg_id": "",
"content": {
"Subject Line": "Test subject line.",
"Body": "This is <b>a body</b>."
},
"sender_name": "Joe Peschi",
"target_email": "[email protected]",
"email_account": {
"email_address": "**********",
"password": "********"
}
}'
But I can also run a request through Lambda test using the original JSON structure, and it will also work perfectly:
Here's the final code:
import smtplib
from email.message import EmailMessage
from email.utils import make_msgid
def lambda_handler(event, context):
try:
json_body = json.loads(json.loads(json.dumps(event, default=str))["body"])
except:
json_body = ""
if json_body != "":
event = json_body
msg = EmailMessage()
if event["reply_to_msg_id"] != "":
msg['References'] = event["reply_to_msg_id"]
msg['In-Reply-To'] = event["reply_to_msg_id"]
msg['subject'] = "Re: " + event["content"]["Subject Line"]
else:
msg['subject'] = event["content"]["Subject Line"]
msg['from'] = event["sender_name"]
msg['To'] = event["target_email"]
msg['Message-ID'] = make_msgid('random_client_id')
msg.add_header('Content-Type', 'text/html')
msg.set_payload(event["content"]["Body"])
server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
result = {"Message-ID": msg['Message-ID']}
try:
server.login(event["email_account"]["email_address"], event["email_account"]["password"])
server.send_message(msg)
server.quit()
result["Status"] = "Success"
except Exception as E:
result["Status"] = str(E)
return {
'statusCode': 200,
'headers': {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
'body': json.dumps(result),
"isBase64Encoded": False
}
Upvotes: 2
Reputation: 238975
events
through API gateway have different format, and you can't change that for proxy lambda integration. For non-proxy, you can use mapping templates.
To best way to verity the event
structure it is to print it out and inspect, and amend the lambda code if needed if you don't use mapping templates:
print(json.dumps(event, default=str))
Upvotes: 2