0
votes

I have verified the following

  1. AWS SES isn't in Sandbox. I can send email via console to non-verified email ids.
  2. My Lambda function has a role attached with full access to SES and Lambda (since its initial basic testing gave full permissions)

The following below a basic code from AWS documentation, just hard coded my email id. Yet I can't receive any email. The lambda code runs successfully but I don't receive emails.

import json
import os
import boto3
from botocore.exceptions import ClientError
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication

print('Loading function')


def lambda_handler(event, context):
    print("Received event: " + json.dumps(event, indent=2))
    #print("value1 = " + event['key1'])
    #print("value2 = " + event['key2'])
    #print("value3 = " + event['key3'])
    #return event['key1']  # Echo back the first key value
    #raise Exception('Something went wrong')
    SENDER = "[redacted email]"
    RECIPIENT = event['email']
    CONFIGURATION_SET = "ConfigSet"
    AWS_REGION = "us-east-2"
    SUBJECT = "Contact Us Form Details"
    # The email body for recipients with non-HTML email clients.
BODY_TEXT = "Hello,\r\nPlease see the attached file for a list of customers to contact."

# The HTML body of the email.
BODY_HTML = """\
<html>
<head></head>
<body>
<h1>Hello!</h1>
<p>Please see the attached file for a list of customers to contact.</p>
</body>
</html>
"""

# The character encoding for the email.
CHARSET = "utf-8"

# Create a new SES resource and specify a region.
client = boto3.client('ses',region_name='us-east-2')

# Create a multipart/mixed parent container.
msg = MIMEMultipart('mixed')
# Add subject, from and to lines.
msg['Subject'] = "Contact Us Form Details" 
msg['From'] ="[redacted email]" 
msg['To'] = "[redacted email]"

# Create a multipart/alternative child container.
msg_body = MIMEMultipart('alternative')

# Encode the text and HTML content and set the character encoding. This step is
# necessary if you're sending a message with characters outside the ASCII range.
textpart = MIMEText(BODY_TEXT.encode(CHARSET), 'plain', CHARSET)
htmlpart = MIMEText(BODY_HTML.encode(CHARSET), 'html', CHARSET)

# Add the text and HTML parts to the child container.
msg_body.attach(textpart)
msg_body.attach(htmlpart)

# Define the attachment part and encode it using MIMEApplication.
#att = MIMEApplication(open(ATTACHMENT, 'rb').read())

# Add a header to tell the email client to treat this part as an attachment,
# and to give the attachment a name.
#att.add_header('Content-Disposition','attachment',filename=os.path.basename(ATTACHMENT))

# Attach the multipart/alternative child container to the multipart/mixed
# parent container.
msg.attach(msg_body)

# Add the attachment to the parent container.
#msg.attach(att)
print(msg)
try:
    #Provide the contents of the email.
    response = client.send_raw_email(
        Source="[redacted email]",
        Destinations=[
            "[redacted email]"
        ],
        RawMessage={
            'Data':msg.as_string(),
        },
        #ConfigurationSetName=CONFIGURATION_SET
    )
# Display an error if something goes wrong. 
except ClientError as e:
    print(e.response['Error']['Message'])
else:
    print("Email sent! Message ID:"),
    print(response['MessageId'])

Attaching my cloud watch logs for reference

enter image description here

2
have you checked your spam folder - Arun K
If you run the same code outside of Lambda (eg on your own computer or an EC2 instance), does it work? Also, is the Lambda function connected to a VPC? Does your CloudWatch debug log show all your print() statements? - John Rotenstein
Your code seems to lose its indenting at the BODY_TEXT line. Is that due to the way it was pasted into StackOverflow, or is that actually how your code is written in the Lambda function? - John Rotenstein
@JohnRotenstein "Received event: " print statement gets printed, but no statement after that. Ideally i expect print(msg) also to be printed. lamda function is not connected to any VPC. When i try the python code standalone from my local laptop, e-mail gets sent successfully. - Vinod Jayachandran
@JohnRotenstein Added screenshot of cloudwatch logs for a single call , hope that helps - Vinod Jayachandran

2 Answers

4
votes

If your code is really what you have displayed to us, then the reason that it is not sending the email is because half your code is not being executed.

def lambda_handler(event, context):
    print("Received event: " + json.dumps(event, indent=2))
    #print("value1 = " + event['key1'])
    #print("value2 = " + event['key2'])
    #print("value3 = " + event['key3'])
    #return event['key1']  # Echo back the first key value
    #raise Exception('Something went wrong')
    SENDER = "[redacted email]"
    RECIPIENT = event['email']
    CONFIGURATION_SET = "ConfigSet"
    AWS_REGION = "us-east-2"
    SUBJECT = "Contact Us Form Details"
    # The email body for recipients with non-HTML email clients.
BODY_TEXT = "Hello,\r\nPlease see the attached file for a list of customers to contact."

When AWS Lambda executes the function, it calls lambda_handler(). As per Python formatting, it will execute all indented lines since they form part of the function. This includes your print() statement.

However, starting with the BODY_TEXT = ... line, there is no indenting. This means that the code is part of the "main" program, and not part of the lambda_handler() function. It would be executed when the Lambda container is first instantiated, but not when the function is triggered.

Bottom line: If this is your actual code, you need to fix your indents.

0
votes

If you are not getting any errors from when executing the lambda, then most probably you are not hitting the SES API. From what I see in your code, you are missing an Access Key Id and Secret Access Key. Try configuring your boto client like this:

client = boto3.client(
    'ses',
    region_name=region,
    aws_access_key_id='aws_access_key_string',
    aws_secret_access_key='aws_secret_key_string'
)

Also make sure that your lambda is deployed in the same region as your SES. I see you are using us-east-2. Another discrepancy I see, which is also in the documentation is that in the official AWS documentation, Destinations is actually Destination. Try it without the 's'. Can you also paste the cloudwatch logs for the lambda. I see it should print the message Id upon success. Does it?