Sending Emails with Python is too easy?

Ashish Agarwal

Published on Wednesday, Apr 24, 2024

Have you ever tried to make a Python project that can send you emails? Well, that's ez!

Sending Emails with Python

You tried several mailing service. SMTPLib? No, it did not work (to me too). MailGun? It is not always free.

Google Accounts used to have Less Secure Access, which was recently removed. However, in addition, they added a Gmail API which is more secure as well as with good functionallities.

I'll be demonstrating you step-by-step to how to use Python to send emails.

At the Conclusion section, you can see a project I made that also uses this Gmail API for verifying emails when you register on the website.

Setting up

Like always, a terminal and

virtualenv .venv
source .venv/source/activate

Boom!

Setting up the project

Go to GCP and create new project https://console.cloud.google.com/projectcreate

Make a project

Once it's created, select it. From the sidebar, go to APIs & Services, Library and enable the Gmail API.

API Library

Then, you should see like this, asking you that you may need credentials. We do not need to create credentials from here. Just verify that you are at a similiar screen as me.

Gmail API is now enabled

Go to OAuth Consent screen, and choose User Type as External.

OAuth Info

You will have to specify things like:

  • App Name

  • User Support Email

  • App Logo

  • Developer's Email Address

Specify them as you wish. Application's home page, privacy policy, TOC etc is optional.

Any info you are specifying out of these are not shared. Even the app name does not make a difference, it is only what you will see when you are authenticating, not your users.

Add your email to user support and developer's email. You can specify app name like My Newsletter, it does not matter or change something worth.

Continue

Leave scopes as it is, and add your email (or the email you will use as your email sender, the from: email address, like maybe a test account's email address to it).

I recommend you to not use your main or valuable email address as a test user, or do not authenticate with it as Google auto-spam might report you.

For testing mode, only 100 test users can  be allowed.

OAuth created

OAuth created

Scroll down and verify you added your test account (the email address of the google account you own that you will be using as the email sender) is there, or add it.

You can publish your app however there is no need if you are doing this for your own. Additionally, they may ask you some questions so its fine in testing.

Go to credentials

Go to credentials and click create credentials, choose OAuth Client ID and then...

Create credentials for a desktop application

The name is not shown to anyone except you so it's just fine as it is. Click CREATE.

Credentials have been created

Now as your credentials are created, download and save them to your project's directory as credentials.json.

The coding

Create a file named app.py in your project folder. Your project should be like this:

Folder structure

First, install the following libraries (make a requirements.txt and install from it, if you prefer):

  • google-api-python-client

  • google-auth-httplib2

  • google-auth-oauthlib

  • requests

The python script

This is your magical weapon to send emails! Put this code in your app.py, confirming that you have a credentials.json in the same directory and you installed all the packages.

import base64
import os.path
import pickle
from email.mime.text import MIMEText

from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from requests import HTTPError

SCOPES = ["https://www.googleapis.com/auth/gmail.send"]


def email(to, subject, body):
    creds = None
    if os.path.exists('token.pickle'):
        with open('token.pickle', 'rb') as token:
            creds = pickle.load(token)
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        with open('token.pickle', 'wb') as token:
            pickle.dump(creds, token)

    service = build('gmail', 'v1', credentials=creds)
    message = MIMEText(body, 'html')
    message['to'] = to
    message['subject'] = subject
    create_message = {'raw': base64.urlsafe_b64encode(message.as_bytes()).decode()}
    try:
        message = (service.users().messages().send(userId="me", body=create_message).execute())
        return True
    except HTTPError as error:
        return False

I took this code lying on the surface of the web

Great. At the last, add few lines to test our application. Call the email method with to as your email (the destination) and some dummy subject and body (body allows HTML).

sendMyEmail = email(to="your_email_here@gmail.com", subject="Hi there bro!", body="What a <b>nice</b> day!")
if sendMyEmail:
  print("Email sent successfully. Check your inbox!")
else:
  print("Sorry, I cannot send the email.")

The email will not be sent on errors like Address Not Found or something, so try to set the to email to a account you own and then see.

Test the app

Finally, run the file.

Authorize needed

It should open a browser window and give you a URL to authorize. This is only needed to be done once as your token will be saved to token.pickle. Please addtoken.pickle to your .gitignore as it may leak access to your account.

Complete the authorization procedure with your testing account (the account will only work if it is in the Testing Users list for the OAuth app).

Security warning

As you can see, you will be warned by Google as this app is on testing. We can continue as because we know what we are doing.

Permissions

The app can send emails on behalf of my google account. So, use either your testing, or the product one, not your main!

Authentication completed

Now the authorization flow has been completed, close the authorization tab and visit back to your terminal, did the email got sent?

It worked!

EMAIL SENT!!

Ok good the email is sent. Can I check my inbox?

Email in inbox!

Seriously, I've got it in my inbox now. The email is in HTML, as the <b> is working as intended to bold the text and...

Email Info

There isn't visible differences to know if this email is automated or what, but it still shows in Primary (Person-to-person emails go in primary).

Wrapping up

Congrats on making a python project that can send emails! Here's what you can use this for:

  • Adding email vertification for signup/login

  • Making your newsletter website (flask is very easy with this)

Just for a example, visit <cutyoururl.tech>, my URL shortener with Python+Flask+Gmail API that uses this same method to verify emails. GitHub: {% embed https://github.com/ashishagarwal2023/CutYourURL %}. Can you give it a star?

Subscribe to newsletter

All the blog news straight to your box!

Sign up for our newsletter

You will receive a confirmation email and you may unsubscribe at any time.