Skip to content

Instantly share code, notes, and snippets.

@rambabusaravanan
Last active November 7, 2023 03:35
Show Gist options
  • Save rambabusaravanan/dfa2b80369c89ce7517855f4094367e6 to your computer and use it in GitHub Desktop.
Save rambabusaravanan/dfa2b80369c89ce7517855f4094367e6 to your computer and use it in GitHub Desktop.
AWS Lambda Function to send SMTP Email
import smtplib
import os
def send_email(host, port, username, password, subject, body, mail_to, mail_from = None, reply_to = None):
if mail_from is None: mail_from = username
if reply_to is None: reply_to = mail_to
message = """From: %s\nTo: %s\nReply-To: %s\nSubject: %s\n\n%s""" % (mail_from, mail_to, reply_to, subject, body)
print (message)
try:
server = smtplib.SMTP(host, port)
server.ehlo()
server.starttls()
server.login(username, password)
server.sendmail(mail_from, mail_to, message)
server.close()
return True
except Exception as ex:
print (ex)
return False
def lambda_handler(event, context):
# initialize variables
username = os.environ['USERNAME']
password = os.environ['PASSWORD']
host = os.environ['SMTPHOST']
port = os.environ['SMTPPORT']
mail_from = os.environ.get('MAIL_FROM')
mail_to = os.environ['MAIL_TO'] # separate multiple recipient by comma. eg: "abc@gmail.com, xyz@gmail.com"
origin = os.environ.get('ORIGIN')
origin_req = event['headers'].get('Host')
reply_to = event['queryStringParameters'].get('reply')
subject = event['queryStringParameters']['subject']
body = event['body']
# vaildate cors access
cors = ''
if not origin:
cors = '*'
elif origin_req in [o.strip() for o in origin.split(',')]:
cors = origin_req
# send mail
success = False
if cors:
success = send_email(host, port, username, password, subject, body, mail_to, mail_from, reply_to)
# prepare response
response = {
"isBase64Encoded": False,
"headers": { "Access-Control-Allow-Origin": cors }
}
if success:
response["statusCode"] = 200
response["body"] = '{"status":true}'
elif not cors:
response["statusCode"] = 403
response["body"] = '{"status":false}'
else:
response["statusCode"] = 400
response["body"] = '{"status":false}'
return response
@hazue
Copy link

hazue commented Apr 29, 2020

Would be great if it has function to send attachment

@LoharG
Copy link

LoharG commented Mar 25, 2021

{
"errorMessage": "'headers'",
"errorType": "KeyError",
"stackTrace": [
" File "/var/task/lambda_function.py", line 32, in lambda_handler\n origin_req = event['headers'].get('origin')\n"
]
}

Function Logs
START RequestId: 57014a4c-2757-447b-930a-7231aba9bd57 Version: $LATEST
[ERROR] KeyError: 'headers'
Traceback (most recent call last):
  File "/var/task/lambda_function.py", line 32, in lambda_handler
    origin_req = event['headers'].get('origin')
END RequestId: 57014a4c-2757-447b-930a-7231aba9bd57
REPORT RequestId: 57014a4c-2757-447b-930a-7231aba9bd57 Duration: 14.10 ms Billed Duration: 15 ms Memory Size: 128 MB Max Memory Used: 49 MB Init Duration: 137.49 ms

Request ID
57014a4c-2757-447b-930a-7231aba9bd57

@LoharG
Copy link

LoharG commented Mar 25, 2021

Getting error after Replace the string 'Host' with 'origin' at line number 32

@ShaktiAhad
Copy link

I wasn’t able to send email using Gmail username/password. I made following changes to make it work.

Create password for external App(In our case Lambda function)

Got to Google Account Security and Scroll down to "Signing in to Google" option. If you don't have 2 step verification on; enable it. Then you will see "App passwords" option. Generate a password for your lambda function.

  • Make sure to copy the Password else you will not be able to copy it later.

Sample lambda function in python to check SMTP server

I have used a this following code to verify my SMTP server is working.

import smtplib, os

def lambda_handler(event=None, context=None):
    sender = os.getenv("SENDER")
    receiver = os.getenv("RECEIVER")
    password = os.getenv("PASSWORD")
    host = os.getenv("SMTPHOST")
    port = os.getenv("SMTPPORT")

    try:
        server = smtplib.SMTP(host, port)
        server.ehlo()
        server.starttls()
        server.login(sender, password)
        server.sendmail(sender, receiver, msg="Subject: Test\n\n This is a test from lambda")
        server.close()
        return True
    except Exception as ex:
        print (ex)
        return False

lambda_handler()

Send attachment using SMTP server

As I have used xlsWriter module to create Excel file, I had to create a lambda layer for that. First I will explain how I created the lambda layer.

xlsWriterlambda layer creation:

Create a file xlsWriter.py on your local ~/Desktop path and copy/paste the following command. It will create xlswriter.zip file on your Desktop.

"""
......This scrpit is for creating xlsWriter lambda layer......
"""
import os

os.system(
    '''
    echo ".............All good! Ready to go!............."
    export ZIP_FILE_NAME="xlswriter.zip" 
    cd ~/Desktop
    mkdir -p python/lib/python3.9/site-packages
    pip3 install XlsxWriter --target ~/Desktop/python/lib/python3.9/site-packages
    zip -r xlswriter.zip ./python 
    echo ".............Check the file:${ZIP_FILE_NAME} on your Desktop............."
    '''
)

After creating the zip file use following steps to upload file and create the layer.

  1. Login to your AWS account
  2. Got to Lambda service
  3. Click Layers under Additional resources from left plane
  4. Click Create layer
  5. Put a name for lambda layer
  6. Upload the xlswriter.zip file.
  7. Copy the ARN from the top right corner. We need the ARN to use the lambda layer in our lambda function.

There are some other fields such as Description, Compatible architectures, Compatible runtimes, etc. These are optionals.

Sample lambda function in python to send an attachment:

  • Lambda function creation and add the lambda layer:
  1. Create a lambda function SMTP_attachment_lambda.
  2. Under Function Overview, Click Layers option just below the function name.
  3. Click Add Layer.
  4. Choose Specify An ARN option paste the layer ARN in the blank field.
  5. Click verify then Add.
  • Make sure you create the excel file in /tmp folder. Else you will get following error "errorMessage": "[Errno 30] Read-only file system: '/hello.xlsx'"
  • Also you need to create __init.py__ file. Else you will get lots of following error "File \"<frozen importlib._bootstrap>\"
  • Lambda Folder tree:
SMTP_attachment_lambda
├── __init.py__
└── lambda_function.py
  • Code:
import smtplib, os, xlsxwriter
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

def lambda_handler(event=None, context=None):
    
    # Create an Excel File
    workbook = xlsxwriter.Workbook('/tmp/hello.xlsx')
    worksheet = workbook.add_worksheet()
    worksheet.write('A1', 'Hello world')
    workbook.close()
    
    # Attach Excel file and send
    sender = os.getenv("SENDER")
    receiver = os.getenv("RECEIVER")
    password = os.getenv("PASSWORD")
    host = os.getenv("SMTPHOST")
    port = os.getenv("SMTPPORT")

    msg = MIMEMultipart()
    msg['From'] = sender
    msg['To'] = receiver
    msg['Subject'] = "Test_email"
    text = """
        This is a test email with an excel file attached. 

        Regards,
        Lambda
    """
    msg.attach(MIMEText(text))
    with open('/tmp/hello.xlsx', 'rb') as file:
            part = MIMEApplication(file.read())
            part.add_header('Content-Disposition',f'attachment; filename={os.path.basename("hello.xlsx")}')
            msg.attach(part)


    try:
        smtp = smtplib.SMTP(host=host, port=port)
        smtp.starttls()
        smtp.login(sender, password)
        smtp.sendmail(sender, receiver, msg.as_string())
        print("Success: Email has been sent")
    except Exception:
        print("Error: Unable to send email")
        raise Exception


lambda_handler()

@ubuntu821
Copy link

python3.6 error
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment