How I deployed an Email Reminder for my Girlfriend with AWS Lambda for free

Xin Zhe Khooi
6 min readOct 3, 2019

--

Create your own email reminder with AWS Lambda & Gmail in 5 simple steps using Python!

We rely on the solar calendar for our daily lives, especially the Gregorian calendar. However, there’s also a different calendar, called the Lunar Calendar. It is widely used for various religious purposes.

My girlfriend practices vegetarian diet on every first (初一) and fifteenth day (十五) of the lunar month in the Chinese Lunar Calendar. It is not easy to keep track of the lunar calendar unless you are always aware of it.

So, I thought of deploying an automated reminder that sends her a reminder at 12am on every first and fifteenth day of the lunar calendar, as well as the day before them.

Related image
AWS Lambda [Source]

Since, we have 1,000,000 free AWS Lambda requests from AWS every month, it’s free, why not! You may read more about the Free Tier here.

In this article, I will share how I put everything together with AWS Lambda, AWS CloudWatch Events and Gmail in 5 steps.

Overview

We will first start off by getting your Gmail account setup, in order to be able to send emails programmatically with Python.

For our focus today, then we will create an AWS Lambda function for our email reminder, associate it with a Lambda Trigger, in this case, CloudWatch Events. Next, we will define a CloudWatch Event Rule with cron to schedule our email reminder to be executed at a specific time daily.

Lastly, we will finish up with the implementation of the email reminder. I will share the complete implementation as well. From there on, you will be able to implement your own custom reminder from there on!

Step 1: Getting your credentials ready

First things first, depending on your security settings, if you do not have two factor authentication (2FA) turned on for your Google account (which is highly recommended, though), you may refer to allowing less secure apps to access your account. If you have secured your account with 2FA (good!), then you’ll need to generate an app password for this tutorial.

We’ll need that in the following step!

Step 2: Let’s try sending an email!

We’ll be using the popular smtplib Python library as our email client to send out emails, the package itself should be built into your Python interpreter. You will not need to install it separately.

You may copy the following sample code, modify gmail_user, gmail_app_password, and sent_to variables before executing the script.

Note: For the gmail_app_password, is the app password that you have generated in Step 1 if you have 2FA enabled. Else, it will be your Gmail password.

import smtplibgmail_user = YOUR_GMAIL_ACCOUNT_HERE
gmail_app_password = YOUR_GMAIL_PASSWORD_OR_APP_PASSWORD
sent_from = gmail_user
sent_to = ['someone@gmail.com', 'anyone@gmail.com']
sent_subject = 'Test'
sent_body = 'This is a test'
email_text = """\
From: %s
To: %s
Subject: %s
%s
""" % (sent_from, ", ".join(sent_to), sent_subject, sent_body)
try:
server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
server.ehlo()
server.login(gmail_user, gmail_app_password)
server.sendmail(sent_from, sent_to, email_text.encode("utf-8"))
server.close()
print(email_text)
print('Email sent!')
except Exception as exception:
print("Error: %s!\n\n" % exception)

Execute the script, and you should get an email in your inbox. If you have issues with it, you can refer to this post. We will do some modifications later on in Step 5 to prevent our app password to be stored as plain text in the code.

Step 3: Creating your Lambda function on AWS

Once you got the email sender working, now it’s time to get things setup on Amazon Web Services. We will start with creating a Lambda function on AWS Lambda.

What’s AWS Lambda? AWS Lambda lets you run code without provisioning or managing servers. A Lambda function refers to the code that is to be executed when it is triggered.

Creating the Lambda function

Once you get your Lambda function created, you will see a lambda_function.py initialized with the lambda_handler as shown as below.

import jsondef lambda_handler(event, context):
# TODO implement
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}

The lambda_handler function will be invoked whenever the Lambda function is triggered. It acts similarly to the main function in a Python program. Hence, all your main program logic and function calls should be executed within here.

Step 4: Associate your lambda function with a Lambda Trigger

Now you have your Lambda function ready, we now need to associate it with a CloudWatch Event Rule as a Lambda Trigger.

For my use case, I will need my Lambda function to be executed every midnight, hence I will be defining a cron expression that schedules my Lambda function to be executed accordingly.

Creating a CloudWatch Event Rule, then defining a cron expression, and associating it with the Lambda function.

A cron expression is a command to an operating system or server for a job that is to be executed at a specified time.

Something to note is that the server time is based at GMT. Hence, you may need to do some simple math to reflect your timezone. As I want my Lambda function to be executed every day at 12.01am (GMT +8), my expression will be like cron(01 16 * * ? *).

Here’s how the format of a cron expression should look like:

cron(Minutes Hours Day-of-month Month Day-of-week Year)

As a reference, you may refer to AWS’s guide on cron expressions.

You can play around with the cron expression and you will be able to see a preview of the trigger date(s), when creating the rule. Not to forget, set the target of the rule that you have created to the Lambda function that you have created in Step 3, which is Test .

Step 5: Finishing up with the Lambda function!

Last but not least, it’s time to finish up the Lambda function of the email reminder with the implementation.

Tip: Use minimal imports if possible, to avoid the hassle to pushing the dependencies with additional Lambda layers!

To avoid additional imports apart from the default libraries in Python, I have included the complete Lunar Calendar implementation in my code. I have added separation comments to clearly differentiate between functions.

How does the code works?

It will start with the lambda_handler followed by a call to the lunar_check function to perform the lunar calendar conversion. If it’s the 1st (初一) or 15th (十五) day and also a day before the 1st and 15th of the lunar calendar, the send_email function will be invoked to send out the email reminder.

Note that in the source code above, I have a slightly different statement for the gmail_app_password which is below:

gmail_app_password = os.environ['MAIL_PASS']

This is to prevent our credentials to appear as plain text in the source code. We will treat it as an environment variable, where AWS will encrypt it for us.

Setting the MAIL_PASS environment variables for the Lambda function

After getting everything done, save your function and you can test your function out! (If your function is time dependent, you should hard code the time when testing it out, to make sure that it will send out emails normally ;))

The reminder is good to go!

Conclusion

In this article, I have shown steps on how to set our Gmail accounts to be able to send emails programmatically with Python’s smtplib , creating a Lambda function on AWS, configuring a AWS CloudWatch Event Rule with a cron expression associating it with our Lambda function to trigger it accordingly, shared my implementation for my lunar calendar email reminder as well as shared ways on securing your credentials with environment variables.

The Lunar Calendar I’ve shown above is just a mere example on how AWS Lambda together with AWS CloudWatch can be so useful in scheduling periodic tasks, especially for generating reminders.

You can easily develop your own Email Reminder with your own implementation and use case, you’ll only need the send_email from this example, and also the lambda_handler to start off with.

If you have any questions about, do hit me up at the comment section below! I would be glad to help!

--

--