Python Email-Bot with GCP and Gmail API
Intro
Need to create an email dispatch server? Gotta spam your friends with fantasy league updates?
Look no further! Follow these steps and you’ll have your Python Email-Bot running in less than 20 minutes.
Checklist
Before you get started, make sure you have the following:
- A Gmail Account
- A GCP Account
Part 1: Google Cloud Configurations
- Create a new google cloud project
2. Ensure the Gmail API is enabled
3. Create an OAuth Consent Screen
If the GCP Project you’re using is associated with an Organization you can select Internal, otherwise you’ll have to use the External option.
Populate the name and email fields as shown below.
Add your desired scopes. In this case, we’ll leave it blank.
Test users can be added if this is one of your requirements, but bear in mind, tokens generated in the test phase will only last one week before expiring completely.
4. Create credentials for our app
Click the Create Credentials button and select OAuth client ID
From there, we’ll select Desktop App
Make sure to download the generated keys after hitting confirm!
We’re now ready to build the bot!
Part 2: Python Script
Note: Most of these steps can be recreated using the Quickstart guide in the Gmail API documentation here
- Install the necessary libraries
pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
2. Import necessary modules and define your scopes to compose emails.
You can read more about the scopes here.
from __future__ import print_function
import base64
import mimetypes
from email.message import EmailMessage
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
SCOPES = ['https://www.googleapis.com/auth/gmail.compose']
3. Generate our auth token.
Remember those OAuth credentials we just downloaded? Rename the file to credentials.json and paste them in the root directory of your Python project.
creds = None
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# If there are no (valid) credentials available, let the user log in.
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)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
This bit of code will do the following:
- Check for an existing OAuth token — if it exists and it’s not expired, use it
- If there’s no valid token, use the downloaded credentials and create a new token.
4. Create the email!
try:
# create gmail api client
service = build('gmail', 'v1', credentials=creds)
mime_message = EmailMessage()
# headers
mime_message['To'] = "YOUR_EMAIL"
mime_message['From'] = 'TARGET_EMAIL'
mime_message['Subject'] = 'Sent from automated email server'
# text
mime_message.set_content(
"<p> Hi, this is automated mail with attachment on behalf of a Gmail bot</p><p>No need to reply, dw</p> "
, subtype="html"
)
# attachment
attachment_filename = 'YOURFILE.pdf'
# guessing the MIME type
type_subtype, _ = mimetypes.guess_type(attachment_filename)
maintype, subtype = type_subtype.split('/')
with open(attachment_filename, 'rb') as fp:
attachment_data = fp.read()
mime_message.add_attachment(attachment_data, maintype, subtype, filename="YOUR_FILENAME.pdf")
encoded_message = base64.urlsafe_b64encode(mime_message.as_bytes()).decode()
create_message = {
'raw': encoded_message
}
# pylint: disable=E1101
send_message = (service.users().messages().send
(userId="me", body=create_message).execute())
except HttpError as error:
print(F'An error occurred: {error}')
send_message = None
return send_message
5. This will leave with you an end file that looks something like this!
from __future__ import print_function
import base64
import mimetypes
import os
from email.message import EmailMessage
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
SCOPES = ['https://www.googleapis.com/auth/gmail.compose']
def gmail_send_attachment():
creds = None
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# If there are no (valid) credentials available, let the user log in.
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)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
try:
# create gmail api client
service = build('gmail', 'v1', credentials=creds)
mime_message = EmailMessage()
# headers
mime_message['To'] = "YOUR_EMAIL"
mime_message['From'] = 'TARGET_EMAIL'
mime_message['Subject'] = 'Sent from automated email server'
# text
mime_message.set_content(
"<p> Hi, this is automated mail with attachment on behalf of a Gmail bot</p><p>No need to reply, dw</p> "
, subtype="html"
)
# attachment
attachment_filename = 'YOURFILE.pdf'
# guessing the MIME type
type_subtype, _ = mimetypes.guess_type(attachment_filename)
maintype, subtype = type_subtype.split('/')
with open(attachment_filename, 'rb') as fp:
attachment_data = fp.read()
mime_message.add_attachment(attachment_data, maintype, subtype, filename="YOUR_FILENAME.pdf")
encoded_message = base64.urlsafe_b64encode(mime_message.as_bytes()).decode()
create_message = {
'raw': encoded_message
}
# pylint: disable=E1101
send_message = (service.users().messages().send
(userId="me", body=create_message).execute())
except HttpError as error:
print(F'An error occurred: {error}')
send_message = None
return send_message
if __name__ == '__main__':
gmail_send_attachment()
You’re good to go! Run and enjoy!