Send Scheduled Emails from Python and Flask with Twilio SendGrid

December 01, 2021
Written by
Reviewed by

Send Scheduled Emails from Python and Flask with Twilio SendGrid

Twilio SendGrid eliminates many of the complexities of sending email. In a previous tutorial, you learned how to use SendGrid’s SMTP server to send emails to your users from a Python and Flask application. But how do you schedule your emails so that they are sent at a specific time?

In this short tutorial you will learn how to use SendGrid’s email scheduling options, which will save you from having to implement your own background scheduling.

Requirements

To work on this tutorial you will need the following items:

  • Python 3.6 or newer. If your operating system does not provide a Python 3.6+ interpreter, you can go to python.org to download an installer.
  • A free Twilio SendGrid account. If you are new to Twilio Sendgrid you can create a trial account. With a trial account you can send 100 emails per day forever.

Create a Flask project

Find an appropriate location for your project and create a directory for it:

mkdir flask-sendgrid-scheduled
cd flask-sendgrid-scheduled

Now create a Python virtual environment where the dependencies of the project are to be installed. For Mac and Unix users, the commands are:

python3 -m venv venv
source venv/bin/activate

For Windows users, the commands are:

python -m venv venv
venv\Scripts\activate

For this project, you are going to use Flask, the Flask-Mail extension and the python-dotenv package. Install them all in your virtual environment:

pip install flask flask-mail python-dotenv

For the purposes of this tutorial, the following Flask application will suffice. Create and open a file named app.py and enter the following code in it using your favorite text editor or IDE:

import os
from flask import Flask
from flask_mail import Mail, Message

app = Flask(__name__)
app.config['MAIL_SERVER'] = 'smtp.sendgrid.net'
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USERNAME'] = 'apikey'
app.config['MAIL_PASSWORD'] = os.environ.get('SENDGRID_API_KEY')
mail = Mail(app)

This short application configures all the email related settings so that you can send emails through your SendGrid account. Note how the email password is sourced from an environment variable. You will define this variable in the next section.

SendGrid configuration

To send emails with SendGrid you need to authenticate with an API key. If you don’t have one yet, log in to your SendGrid account, then click on the left sidebar, select Settings and then API Keys. Click the “Create API Key” button and provide the requested information to create your key. For detailed step-by-step instructions, follow the basic tutorial first.

Once you have your key, create and open a .env file in your Flask project directory, and paste the key as follows:

SENDGRID_API_KEY=<your-sendgrid-key-here>

Send a test email

You are now ready to send a test email. Open a Flask shell with the following command:

flask shell

Now you can configure and send a test email from the Python prompt. First, create a message object and set the subject, sender and recipients:

from app import Message
msg = Message(subject='Test Email', sender='youremail@example.com', recipients=['youremail@example.com'])

Here you should replace youremail@example.com with a valid email address you have access to. If you prefer, you can use different email addresses for the sender and the recipient. You can also use multiple recipient addresses if you like.

When implementing an email sending solution in production, it is recommended that you authenticate the domain you are sending email from to improve deliverability.

Next, set the body of the email:

msg.body = 'This is a test email.'

The body attribute defines a text-only email. If you want to also provide a rich-text version in HTML, you can assign it to the msg.html attribute.

Your message is now complete. You can send it as follows:

from app import mail
mail.send(msg)

In a few seconds, the email should arrive in your inbox. The original Flask email sending tutorial has a “If Your Emails Aren’t Delivered” section that describes how to troubleshoot emails that aren’t delivered.

Schedule an email

You are now ready to schedule an email, from the same shell session. Create a new message:

msg = Message(subject='Test Email', sender='youremail@example.com', recipients=['youremail@example.com'])
msg.body = 'This is a scheduled test email.'

And here comes the magic. You can use the send_at extension from SendGrid to provide a delivery time in Unix timestamp units. In the following example, the email is scheduled to be sent two minutes later:

from time import time
import json
msg.extra_headers = {'X-SMTPAPI': json.dumps({'send_at': time() + 120})}

That’s it! The X-SMTPAPI custom header is an extension supported by SendGrid’s SMTP server that allows applications to pass additional sending instructions as a JSON blob. The expression time() + 120 refers to the current time plus 120 seconds, or in other words, two minutes from now. Send the email like you did before:

mail.send(msg)

Nothing will happen immediately, but about two minutes later you should have the scheduled email in your inbox.

The send_at option is documented in detail. In the same page you can also learn about send_each_at, which allows you to provide a list of timestamps, one per recipient in a multi-recipient email.

Conclusion

I hope this was a useful trick that you can add to your email sending toolbox. The X-SMTPAPI header supports several other extensions, so be sure to check its documentation to learn about more cool email features.

Happy email scheduling!

Miguel Grinberg is a Principal Software Engineer for Technical Content at Twilio. Reach out to him at mgrinberg [at] twilio [dot] com if you have a cool project you’d like to share on this blog!