Send e-mail using SES via Lambda function & connect with SQS request (AWS, Python, Emails,)
AWS Lambda SQS SES API Request

Send e-mail using SES via Lambda function & connect with SQS request (AWS, Python, Emails,)

Most email providers come with the limitation of daily outgoing emails as for example Gmail limited with a maximum outgoing email limit of 3000 only. To scale up from this point the best solution is to use the AWS SES server which gives 50 000 emails per day and 14 emails per second for outgoing as starting average rate.

The following guide, it will show how to set up AWS SES with Lambda connection successfully.

Requirments

  • AWS Lambda
  • AWS SES (Prefer production version due to sandbox got limitation)
  • Two AWS SQS
  • IAM Account


Step 1 - Create AWS SES

Amazon Simple Email Service Classic - Follow the following simple steps to create an identity.

No alt text provided for this image


* Choose identity type as "Email address", then enter preferred marketing email address in the text field and create an identity (marketing@example.com).


Step 2 - Create AWS Lambda

Create Lambda function with runtime Python 3.8, in options as execution role choose "Create a new role with basic Lambda permissions" & rest fo the advance settings leave it blank.

Refer to the following link to view SES send_email function in AWS SDK for Python

And create lambda function with below snip code

import json
import boto3
from botocore.exceptions import ClientError


def lambda_handler(event, context):
    
    
    emailData = event['Records'][0]["messageAttributes"]
    # print(emailData['fromName'])
    
    # Replace sender@example.com with your "From" address.
    # This address must be verified with Amazon SES.
    SENDER = emailData['fromName']['stringValue'] + " <marketing@example.com>"


    # Replace recipient@example.com with a "To" address. If your account 
    # is still in the sandbox, this address must be verified.
    RECIPIENT = emailData['toEmail']['stringValue']
    
    print (emailData)
    
    if 'toCCEmail' in emailData:
      CC_RECIPIENT = emailData['toCCEmail']['stringValue']
      DESTINATION={
                        'ToAddresses': [
                            RECIPIENT,
                        ],
                        'CcAddresses': [
                            CC_RECIPIENT,
                        ],
                        'BccAddresses': [
                            'marketingcc@example.com',
                        ]
                    }
      
    else:
      DESTINATION = {
                        'ToAddresses': [
                            RECIPIENT,
                        ],
                        'BccAddresses': [
                            'marketingcc@example.com',
                        ]
                    }
    
    
    # Specify a configuration set. If you do not want to use a configuration
    # set, comment the following variable, and the 
    # ConfigurationSetName=CONFIGURATION_SET argument below.
    #CONFIGURATION_SET = "ConfigSet"
    
    # If necessary, replace us-west-2 with the AWS Region you're using for Amazon SES.
    AWS_REGION = "ap-southeast-2"
    
    # The subject line for the email.
    SUBJECT = emailData['subject']['stringValue']
    
    # The email body for recipients with non-HTML email clients.
    # BODY_TEXT = ("Amazon SES Test (Python)\r\n"
    #              "This email was sent with Amazon SES using the "
    #              "AWS SDK for Python (Boto)."
    #             )
                
    # The HTML body of the email.
    BODY_HTML = emailData['body']['stringValue']          
    
    # The character encoding for the email.
    CHARSET = "UTF-8"
    
    # Create a new SES resource and specify a region.
    client = boto3.client('ses',region_name=AWS_REGION)
    
    # Try to send the email.
    try:
        #Provide the contents of the email.
        response = client.send_email(
            Destination = DESTINATION,
            Message={
                'Body': {
                    'Html': {
                        'Charset': CHARSET,
                        'Data': BODY_HTML,
                    },
                    # 'Text': {
                    #     'Charset': CHARSET,
                    #     'Data': BODY_TEXT,
                    # },
                },
                'Subject': {
                    'Charset': CHARSET,
                    'Data': SUBJECT,
                },
            },
            Source=SENDER,
            # If you are not using a configuration set, comment or delete the
            # following line
            #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'])
        print(RECIPIENT)
    
    return {
        'statusCode': 200,
        'body': json.dumps(response)
    }
    
        


"SENDER" needs to declare confirmed email identity between "< > " brackets, if the system requires multiple outgoing emails, it can be pass through the SQS data but in this scenario, SES confirmed identify email hardcoded in the lambda function.

"DESTINATION " created with two options, one option to include CC emails and the other option to send emails without CC

* To check & store outgoing emails there is an option to connect with AWS S3 but as an easy solution all the emails are BCC into different email address which can access anytime also will be easy to search for outgoing emails through the email server

"Message - Body" comes with two options "Html" or "Text", depending on the requirement it should be chosen for the outgoing emails


Step 3 - Create Two SQS

AWS SQS (for this process required two SQS)

  1. Create first SQS to queue for outgoing emails with basic Access policy (Name: OutgoingEmailQueue) (Type - Standard)
  2. Create a second SQS to capture failed emails with basic Access policy ( Name: OutgoingEmailFailedQueue) (Type - Standard)

Create another new IAM Account to access SQS

In AWS IAM Console create a new User with Programmatic access & grant the AWS policies as follow (Name: SQS_User)

  • AmazonSQSFullAccess
  • AWSLambdaSQSQueueExecutionRole

Update previously created SQS (OutgoingEmailQueue) Access policy (Permissions) to gain access via newly created IAM Account. Eg:

{
  "Version": "2008-10-17",
  "Id": "__default_policy_ID",
  "Statement": [
    {
      "Sid": "__owner_statement",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::account_id:root"
      },
      "Action": "SQS:*",
      "Resource": "arn:aws:sqs:region_code:account_id:OutgoingEmailQueue"
    },
    {
      "Sid": "__sender_statement",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::account_id:user/SQS_User"
      },
      "Action": "SQS:SendMessage",
      "Resource": "arn:aws:sqs:region_code:account_id:OutgoingEmailQueue"
    }
  ]
}        


Connect SQS (OutgoingEmailQueue) with Dead Letter Queue

Choose the dead letter queue option in OutgoingEmailQueue SQS. Press the edit button then select option enabled, It will open up to search for other SQS listed in your account in the same region. Select previously created "OutgoingEmailFailedQueue" SQS in a dead letter queue option and press save.


If any further question related to this scenario, Please add in the comment section, I will try my best to answer. Also if this article useful for development don't forget to leave feedback in the comment section.


Stop Complaining & Start with Implementation

Thank you
Gayan Jayanath

I do not know why do you stop at step Connect SQS (OutgoingEmailQueue) with Dead Letter Queue. Can you continue update this post with more detail

Like
Reply

Thanks for your article. I have a question - why do you need to set up a new IAM user? Can you just add permissions to an existing user? Thanks

Like
Reply

To view or add a comment, sign in

More articles by Gayan Jayanath

Others also viewed

Explore content categories