HowTo Use Gmail API to send emails
Using Gmail API to send emails
You can find very specific details on how to use the Gmail API for many different purposes.
This page skips over a lot of the details and provides a quick reference on how to send an email using the Gmail API.
Enable Gmail API
You will need to select or create a Google project and add the "Gmail API" to the list of APIs & Services panel as shown on the Google Cloud panel below. One can get to your Google Project here: Google Project. Then navigate within the Google Cloud console using the following: Go to Menu > APIs & Services > OAuth consent screen. Next, navigate to Menu > APIs & Services > Credentials and click Create Credentials > OAuth client ID. Enter a name for the credential.
Download Oauth JSON Credentials
You will need to enable/add the Oauth client option on the credentials panel as shown below and then press the download button to download the credentials file.
You can use the following command to format the downloaded JSON file:
cat ~/Downloads/client_secret_*.json | jq
The output of the above command will produce something similar to the following (where "..." will contain values specific to your authentication):
{
"installed": {
"client_id": "...",
"project_id": "...",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_secret": "...",
"redirect_uris": [
"http://localhost"
]
}
}
Note, for the example below save this to the default file location using these commands.
install -d -D -m 700 ~/.local/credentials
install -m 600 ~/Downloads/client_secret_*.json ~/.local/credentials/email-project-secret.json
Sample Python Script
The following python script (send-via-gmail-api.py) can be used to send emails.
#!/usr/bin/python3
#
# Virtual Environment:
#!/home/<user>/path/to/venv/bin/python3
#
# NOTE: In order to run this you need to add the following packages to the system
#
# sudo dnf install python3-google-api-client python3-oauth2client
import base64
import httplib2
import oauth2client
import os
from email.mime.text import MIMEText
from googleapiclient.discovery import build
from oauth2client import client, tools, file
SCOPES = 'https://www.googleapis.com/auth/gmail.send'
# By default we will look for credentials files under ~/.local/credentials, you should set the permissions
# to this directory to 700
CREDENTIAL_DIR = os.getenv('CREDENTIALS_DIR', os.path.join(os.path.expanduser('~'), '.local', 'credentials'))
# You will need to download this JSON file from Google project that you have enabled the
# Gmail API on. NOTE: This is typically only needed to generate the limited scope credentials JSON
# file once at which point that is the only file that will typically be used when the script
# needs to present itself as legitimate when sending email messages out.
# You can export GOOGLE_PROJECT_SECRETS to the location of your credentials file to override default location
PROJECT_OAUTH_SECRET_FILE = os.getenv('GOOGLE_PROJECT_SECRETS', os.path.join(CREDENTIAL_DIR, 'email-project-secret.json'))
APPLICATION_NAME = 'Gmail API Python Send Email'
def get_credentials():
if not os.path.exists(CREDENTIAL_DIR):
os.makedirs(CREDENTIAL_DIR)
# Actual authorization file for our script with necessary scope set so we can send out email
credential_path = os.path.join(CREDENTIAL_DIR, "gmail-api-email-send.json")
credentials = False
store = oauth2client.file.Storage(credential_path)
if os.path.exists(credential_path):
credentials = store.get()
if not credentials or credentials.invalid:
# Authorization file needs to be (re)created, request a new one using project credentials
# IMPORTANT: When this occurs, you will need to interact with a browser to confirm that
# it is OK to allow the script to send emails on your behalf!
print(f"Need to update/create {credential_path}")
flow = client.flow_from_clientsecrets(PROJECT_OAUTH_SECRET_FILE, SCOPES)
flow.user_agent = APPLICATION_NAME
credentials = tools.run_flow(flow, store)
print(f"Stored credentials to {credential_path}")
return credentials
def send_email(service, sender, to, subject, message_text):
message = MIMEText(message_text, "html")
message['to'] = to
message['from'] = sender
message['subject'] = subject
raw_message = base64.urlsafe_b64encode(message.as_bytes()).decode("utf-8")
message = {'raw': raw_message}
try:
message = service.users().messages().send(userId='me', body=message).execute()
print(f'Message sent, Id: {message["id"]}')
return message
except Exception as error:
print(f'An error occurred: {error}')
return None
def send_email_fixed_font(service, sender, to, subject, message_text):
pre_message_text = "<pre>" + message_text + "</pre>"
message = MIMEText(pre_message_text, "html")
message['to'] = to
message['from'] = sender
message['subject'] = subject
raw_message = base64.urlsafe_b64encode(message.as_bytes()).decode("utf-8")
message = {'raw': raw_message}
try:
message = service.users().messages().send(userId='me', body=message).execute()
print(f'Message sent, Id: {message["id"]}')
return message
except Exception as error:
print(f'An error occurred: {error}')
return None
if __name__ == '__main__':
credentials = get_credentials()
http = credentials.authorize(httplib2.Http())
service = build('gmail', 'v1', http=http)
#
# HTML Content
send_email(service, 'FROM_USER@DOMAIN', 'TO_USER@DOMAIN', 'My Subject', '<p>My Email <b>Body</b></p>')
#
# Read a plain text file - Send content using a Fixed Font (<pre> - Tag)
# TEXT_PATH_FILE_NAME = "/opt/devel/logs/stats.log"
# with open(TEXT_PATH_FILE_NAME, "r") as src:
# contents = src.read()
# fromAddr = 'tom.smith@gmail.com'
# toAddr = 'bill.frame@verizon.net'
# subject = 'Stats Log'
# send_email_fixed_font(service, toAddr, fromAddr, subject, content)
Be aware of the following:
- The first time the script is run it will pull up a browser to confirm that you want to grant permission (this won't be required on subsequent runs).
- You will need to change the FROM_USER@DOMAIN and TO_USER@DOMAIN values at the end of the script to the email accounts that you want to test with.
- It expects to find the oauth credentials JSON file that you downloaded at $HOME/.local/credentials/email-project-secret.json (feel free to change).
- The initial authentication will create a new $HOME/.local/credentials/gmail-api-email-send.json file that will then be used during subsequent invocations.
- Easier to create the initial authentication file on a desktop for the user because a browser will be used for this purpose.
Install Required DNF Packages
The NST distribution does not have all of the Python packages required to run this script by default. You should be able to add the necessary packages via the following command:
sudo dnf install python3-google-api-client python3-oauth2client
Install Required Package Using pip
If you are using a different operating system, you should be able to use "pip" to install the necessary python packages. The example belows show the required python packages using: "pip" in a python virtual environment:
/home/pi/path/to/venv/bin/pip list
Package Version
------------------------ ---------
cachetools 5.5.0
certifi 2024.7.4
charset-normalizer 3.3.2
google-api-core 2.19.1
google-api-python-client 2.142.0
google-auth 2.34.0
google-auth-httplib2 0.2.0
google-auth-oauthlib 1.2.1
googleapis-common-protos 1.65.0
httplib2 0.22.0
idna 3.8
oauth2client 4.1.3
oauthlib 3.2.2
pip 23.0.1
proto-plus 1.24.0
protobuf 5.27.3
pyasn1 0.6.0
pyasn1_modules 0.4.0
pyparsing 3.1.4
requests 2.32.3
requests-oauthlib 2.0.0
rsa 4.9
setuptools 66.1.1
six 1.16.0
smbus 1.1.post2
sugarpie 1.4.0
uritemplate 4.1.1
urllib3 2.2.2
A virtual python environment may be required to install the required packages using "pip". To create a python virtual environment use the following:
python3 -m venv path/to/ven
Install Oauth JSON Credentials
Before running the script, you will need to install the project secrets file in the location that the script will attempt to read it from.
install -d -D -m 700 ~/.local/credentials
install -m 600 ~/Downloads/client_secret_*.json ~/.local/credentials/email-project-secret.json
Initial Run Confirmation
Try running the script initially by hand. This is best done on a desktop since a browser will be required to grant permissions.
./send-via-gmail-api.py
A web browser should appear and you will need to confirm that you want to grant permission to the script before it will be permitted to send emails. Once successfully granted, you should see output similar to the following:
[nst@nst-test ~]$ ./send-via-gmail-api.py Need to update/create /home/nst/.local/credentials/gmail-api-email-send.json Your browser has been opened to visit: https://accounts.google.com/o/oauth2/auth?client_id=... If your browser is on a different machine then exit and re-run this application with the command-line parameter --noauth_local_webserver Authentication successful. Stored credentials to /home/nst/.local/credentials/gmail-api-email-send.json Message sent, Id: 190ade399aa9f639
You should find that a new non-zero length credentials JSON file (gmail-api-email-send.json) has been created under your ~/.local/credentials directory:
[nst@nst-test ~]$ ls -al ~/.local/credentials/ total 8 drwx------ 1 nst nst 100 Jul 13 16:58 . drwx------ 1 nst nst 42 Jul 13 10:46 .. -rw------- 1 nst nst 402 Jul 13 11:05 email-project-secret.json -rw------- 1 nst nst 1410 Jul 13 16:58 gmail-api-email-send.json [nst@nst-test ~]$
Subsequent Runs No Confirmation
Run the script again. Now that the system has been confirmed, subsequent runs should proceed without user interaction.
[nst@nst-test ~]$ ./send-via-gmail-api.py Message sent, Id: 190ade73471976a6 [nst@nst-test ~]$
At this point you should see the emails showing up in your inbox.