Using python boto3 functions and lambda to send attachment to email

·

3 min read

Table of contents

We have a requirement to send a CSV file present in the S3 bucket as an attachment to an email.

AWS Services Used

AWS S3 - For storing CSV file, which needs to be sent to the email

AWS IAM:- Creating roles, and permissions required for services to interact with each other to achieve the final requirement

AWS SES:- Amazon SES is a cloud email service provider that can integrate into any application for bulk email sending.

AWS Lambda:- AWS Lambda is a serverless compute service that runs your code in response to events and automatically manages the underlying compute resources for you

Three components comprise AWS Lambda

  • A function. This is the actual code that performs the task.

  • A configuration. This specifies how your function is executed.

  • An event source (optional). This is the event that triggers the function. You can trigger with several AWS services or a third-party service.

S3 bucket with required permissions include

above policy allows the role attached to lambda to have all permissions(allow) related to S3 for the bucket mentioned

above policy allows the lambda service to access this s3 bucket mentioned

PS:- You can always customize the IAM policies as per your requirement

Add your email ID as verified identity in Amazon SES

And for aws lambda execute permissions role, we have attached below aws managed roles, as mentioned already we can customize it according to our requirement

Write the below python code in the lambda function to execute and send an email accordingly

import os.path
import boto3
import email
from botocore.exceptions import ClientError
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
s3 = boto3.client("s3")
def lambda_handler(event, context):
    print(event)
    SENDER = "<<emailID>>"
    RECIPIENT = "<<emailID>>"
    AWS_REGION = "<<aws-region>>"
    SUBJECT = "Email From S3"
    FILEOBJ = event["Records"][0]
    BUCKET_NAME = str(FILEOBJ['s3']['bucket']['name'])
    print(BUCKET_NAME)
    KEY = str(FILEOBJ['s3']['object']['key'])
    print(KEY)
    FILE_NAME = os.path.basename(KEY)
    print(FILE_NAME)
    TMP_FILE_NAME = '/tmp/' + FILE_NAME
    print(TMP_FILE_NAME)
    s3.download_file(BUCKET_NAME, KEY, TMP_FILE_NAME)
    #print(download)
    ATTACHMENT = TMP_FILE_NAME
    print("attachment" , ATTACHMENT)
    BODY_TEXT = "The Object file was uploaded to S3"
    client = boto3.client('ses',region_name=AWS_REGION)
    msg = MIMEMultipart()
    # Add subject, from and to lines.
    msg['Subject'] = SUBJECT 
    msg['From'] = SENDER 
    msg['To'] = RECIPIENT
    textpart = MIMEText(BODY_TEXT)
    msg.attach(textpart)
    att = MIMEApplication(open(ATTACHMENT, 'rb').read())
    att.add_header('Content-Disposition','attachment',filename=ATTACHMENT)
    msg.attach(att)
    print(msg)
    try:
        response = client.send_raw_email(
            Source=SENDER,
            Destinations=['<<emailID>>'],
            RawMessage={ 'Data':msg.as_string() }
        )
    except ClientError as e:
        print(e.response['Error']['Message'])
    else:
        print("Email sent! Message ID:",response['MessageId'])

Attach your s3 bucket as trigger , so that whenever a new csv file is uploaded into s3 bucket , then the trigger gets initiated and lambda function is triggered

Optional:-

below is the test event JSON you might need to test your lambda

{
  "Records": [
    {
      "eventVersion": "2.1",
      "eventSource": "aws:s3",
      "awsRegion": "us-west-2",
      "eventTime": "1970-01-01T00:00:00.000Z",
      "eventName": "ObjectCreated:Put",
      "userIdentity": {
        "principalId": "AIDAJDPLRKLG7UEXAMPLE"
      },
      "requestParameters": {
        "sourceIPAddress": "127.0.0.1"
      },
      "responseElements": {
        "x-amz-request-id": "C3D13FE58DE4C810",
        "x-amz-id-2": "FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD"
      },
      "s3": {
        "s3SchemaVersion": "1.0",
        "configurationId": "testConfigRule",
        "bucket": {
          "name": "<<bucketname>>",
          "ownerIdentity": {
            "principalId": "A3NL1KOZZKExample"
          },
          "arn": "arn:aws:s3:::<<bcuketname>>"
        },
        "object": {
          "key": "<<filename>>.csv",
          "size": 1024,
          "eTag": "d41d8cd98f00b204e9800998ecf8427e",
          "versionId": "096fKKXTRTtl3on89fVO.nfljtsv6qko",
          "sequencer": "0055AED6DCD90281E5"
        }
      }
    }
  ]
}

Below is a script to fetch inspector findings and write to CSV file and upload to s3 bucket

import json
import boto3
import boto3
import os
import uuid
import email
import csv

#message_text=[]
s3 = boto3.client('s3')
sns = boto3.client('sns')
def lambda_handler(event, context):
    print(len(event['findings']))
    message_text=[""]
    temp_csv_file = csv.writer(open("/tmp/csv_file.csv", "w+"))
    temp_csv_file.writerow(["DESCRIPTION", "REMEDIATION_SUGGESTED", "SEVERITY"])

    for i in range(len(event['findings'])):
        description = event['findings'][i]['description']
        remediation = event['findings'][i]['remediation']['recommendation']
        severity = event['findings'][i]['severity']
        #print(description)
        #print(remediation)
        #print(severity)
        #print("--------------------------------------------------------------------------------------------------------")
        message_text_str =  "DESCRIPTION {0} \n REMEDIATION SUGGESTED {1} \n SEVERITY {2}.\n -------------------------------------------------------------------------------------------------------------------------------------------".format(
            str(event['findings'][i]['description']),
            str(event['findings'][i]['remediation']['recommendation']),
            str(event['findings'][i]['severity']))
        print(message_text_str)
        temp_csv_file.writerow([str(event['findings'][i]['description']),
            str(event['findings'][i]['remediation']['recommendation']),
            str(event['findings'][i]['severity'])])
        message_text.append(message_text_str)
    print(message_text)
    s3.upload_file('/tmp/csv_file.csv', 'inspector-v2-bucket-findings' ,'final_report.csv')
    msg = str("\n".join(message_text))

    #response = sns.publish(
     #      TopicArn = "arn:aws:sns:eu-west-1:386288228052:inspector-v2",
     #      Message = msg,
     #      Subject = "AWS-Inspector findings",
     #       )

CONCLUSION:

In this way we can send attachments to email using aws lambda , we can automate it in our projects based on our requirements