Send Email programmatically with Gmail, Python, and Flask

March 03, 2018
Written by

Screen Shot 2018-03-02 at 10.21.52 AM

Update 2019: 

Google announced they are limiting access to less secure apps to protect G Suite accounts, which means you'll run into more problems sending email with Gmail. Check out this post on how to send emails in Python with Sendgrid for an API driven alternative.

We’ve all been there – you just need to send an email from your application. Maybe it’s password resets or a product notification. You’re probably reading this because you’ve hit that point. Whatever your use case, this post will walk through how to send an email in code using a plain ol’ Gmail account. I’ll also show you how to fix some common errors you’ll see along the way.

What you’ll need

To code along with this post, you’ll need:

In a new folder create a requirements.txt file. This file will help you manage your dependencies in a Python project. We only have one dependency for this project; add the following to your requirements.txt file:

Flask-Mail

You can read more about Flask-Mail in their documentation. Now we can set up our virtualenv, a Python tool that helps manage dependencies, and install our requirements with the following commands:

$ virtualenv env
$ source env/bin/activate
$ pip install -r requirements.txt

Sending an Email in Code

We’ll need to start by configuring our application. In a new file, I called mine send.py, add the following code:

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

app = Flask(__name__)

mail_settings = {
    "MAIL_SERVER": 'smtp.gmail.com',
    "MAIL_PORT": 465,
    "MAIL_USE_TLS": False,
    "MAIL_USE_SSL": True,
    "MAIL_USERNAME": os.environ['EMAIL_USER'],
    "MAIL_PASSWORD": os.environ['EMAIL_PASSWORD']
}

app.config.update(mail_settings)
mail = Mail(app)

Save your EMAIL_USER,  which is your full login like “mycoolemail@gmail.com“, and EMAIL_PASSWORD as environment variables so we’re not hardcoding credentials in our application. To learn more about setting environment variables in your operating system, check out this handy post.

Now we can send an email! Below your configuration code add the following:

if __name__ == '__main__':
    with app.app_context():
        msg = Message(subject="Hello",
                      sender=app.config.get("MAIL_USERNAME"),
                      recipients=["<recipient email here>"], # replace with your email for testing
                      body="This is a test email I sent with Gmail and Python!")
        mail.send(msg)

Make sure to replace the recipients list with a list containing just your email so you can test it out.

Run the program by typing python send.py in your terminal and with a bit of luck (I’ll explain more below) you should receive an email at the recipient address you plugged in.

HOWEVER, there’s a good chance this doesn’t work and you’ll get an email like this.

If you’re getting an smtplib.SMTPAuthenticationError you’ll need to configure a few things in your Google account.

Hacking Gmail Security

OK fine this is all legitimate but Google discourages it in a few ways that we’ll have to reconfigure.

Update the following in your account security settings

1. Allow less secure apps: ON. (https://myaccount.google.com/lesssecureapps)

By default, Google will block connections from insecure apps. That probably includes the one running on your laptop or that you deployed to a random Heroku server.

Be aware that this won’t work for accounts that have 2FA enabled, and please do not disable 2FA on your email. You can either use a separate account or create application-specific passwords instead.


That *might* be all you need, but if you’re still getting authentication errors try the following:

2. Display Unlock Captcha. (https://accounts.google.com/DisplayUnlockCaptcha)

Last but not least, IMAP access will allow you to store a copy of sent mail in your sent mail folder.

3. Enable IMAP Access (https://mail.google.com/mail/#settings/fwdandpop)

Try running your application again and this time it should work. If you’re still getting errors double check that allow less secure apps is on since Gmail was re-disabling it for me sometimes. Wait a moment and then try again.

Why isn’t that an API?

Google offers a free service and free services are magnets for fraud. The security features they’ve implemented aim to discourage people from abusing their mail server. They’ve made it annoying enough to use that I’m sold on switching to a more maintainable solution for larger projects.

The Gmail option is great for sending a few one-off emails for a side project, but I encourage you to check out a service like SendGrid. SendGrid provides a Twilio-like API for sending email and has much nicer error messages when things go awry.

You can find the code for this application on my Github. Have you built email into your application? Find me on Twitter @kelleyrobinson or leave me a comment to let me know what worked (and what didn’t work!) for you.