Using an email system is nice.
But what is more nice is to use automated email system.
In this article I will explain how we can use Gmail API to read messages, edit them (for example marking an email as unread) and more.
In order to follow the guide, create a project with a main.py file. I am using PyCharm IDE but you can use whatever IDE you like.
The Gmail API
We all know Gmail – Google’s email system.
And as a service provided by google it has an API (obviously, otherwise you won’r be reading this :D). Some of the many things we can use the API for are to:
- Manage messages
- Manage labels
- Get attachments
- Send emails
So let’s start. In this article I will connect to the API using Python. If you want to see this guide in other progrramming languages, let me know in the comments below.
The initials
In order to start using the Gmail API, we need to allow it on our account. We can use this link in order to do that. There is also a sample code in this link which you can run and test but it is fairly basic.
Notice: when enabling the gmail API, you will need to download a file called credentials.json
. We will use this file in order to securely connect to the gmail account.
After enabling the gmail API and downloading the credentials.json
file, we now need to install some packages. Use the following command to install theme.
pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
Put the credentials.json
file in the some folder the script is running from.
Set Up Sample
If you want, this is the sample given by google:
from __future__ import print_function
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
def main():
"""Shows basic usage of the Gmail API.
Lists the user's Gmail labels.
"""
creds = None
# The file token.pickle stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
# 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.pickle', 'wb') as token:
pickle.dump(creds, token)
service = build('gmail', 'v1', credentials=creds)
# Call the Gmail API
results = service.users().labels().list(userId='me').execute()
labels = results.get('labels', [])
if not labels:
print('No labels found.')
else:
print('Labels:')
for label in labels:
print(label['name'])
if __name__ == '__main__':
main()
After you followed these steps, we can now move on to the interesting part – fetching the emails!
Gmail API – Fetch Emails
Before Doing any manipulation to emails, we need to fetch them first.
We can do this with the following code:
import pickle
import os
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
def main():
getMessages()
def getMessages():
"""Shows basic usage of the Gmail API.
Lists the user's Gmail labels.
"""
creds = None
# The file token.pickle stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
# 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.pickle', 'wb') as token:
pickle.dump(creds, token)
service = build('gmail', 'v1', credentials=creds)
# Call the Gmail API
labelsResult = service.users().labels().list(userId='me').execute()
labels = results.get('labels', [])
messagesResult = service.users().messages().list(userId='me').execute()
messages = results.get('messages', [])
if __name__ == '__main__':
main()
Another way to get messages is using:
filter = {
'criteria': {
'from': '[email protected]'
}
}
result = gmail_service.users().settings().filters().create(userId='me', body=filter).execute()
print 'Created filter: %s' % result.get('id')
Instead of what we used in this example:
messagesResult = service.users().messages().list(userId='me').execute()
messages = results.get('messages', [])
Now we have all our labels stored in the labels
variable and all our messages id’s stored in the messages
variable.
In order to actually get the messages themselves, we are going to have to fetch them each by their id.
Gmail API – Fetch The Message Itself
Now we have our messages stored in the messages
variable which is of type list
and each element in the list has an id
and a threadId
.
In order to fetch the emails themselves, we need to iterate through the list. Add the following code to getMesseages()
function.
# If there are no messages found
if not messages:
print('No messages found.')
# If found at least one message
else:
for message in messages:
# Get the message it self
m = service.users().messages().get(userId='me', id=message['id']).execute()
# m['snippet'] is the message it self
print(m['snippet'])
Awesome! now we can read our emails using Gmail API with Python.
Getting more details about an email
As mentioned before, the API is not limited to only read messages from gmail. For example, there is much more details about each email then just its snippet.
In order to see all the details about a message, you can use the following function.
def fetchMessage(service, message):
payload = message['payload'] # get payload of the message
header = payload['headers'] # get header of the payload
for h in header:
print(h)
This function displays all the headers an email has.
So for example, if you want to check the email’s subject you could use the following code.
def fetchMessage(service, message):
payload = message['payload'] # get payload of the message
header = payload['headers'] # get header of the payload
for h in header:
# If found the subject header, print its value (the email's subject
if (h['name'] == 'Subject'):
print(h['value'])
Fetching Attachments
As mentioned earlier, we can also use the API to fetch attachment and save them to our local storage.
We can do this with the following code.
# Gets the attachment of the mail and sends it to the printer.
def saveAttachment(service, message):
for part in message['payload']['parts']:
# Check if there is an attachment to the email
if part['filename']:
# Checks if the file is part of the email itself (such as an image)
if 'data' in part['body']:
data = part['body']['data']
# If the file is not a part of the email itself, it is probably an attachment
else:
att_id = part['body']['attachmentId']
# Fetch the attachment
att = service.users().messages().attachments().get(userId='me', messageId=message['id'],
id=att_id).execute()
data = att['data']
# Encode it
file_data = base64.urlsafe_b64decode(data.encode('UTF-8'))
path = part['filename']
# Save to a file stored locally, matching to the `path` variable with the same name of the file in the email
with open(path, 'wb') as f:
f.write(file_data)
In order to use this code, add import base64
at the top of the code.
Also, call the function from the iteration over the messages
list:
saveAttachment(service=service, message=message)
Printing the downloaded attachment
If you also want to automatically print the downloaded attachment, you can use the following code.
Notice: in order to use this code, you have to set a default printer.
To choose a default printer, select the Start button and then Settings . Go to Devices > Printers & scanners > select a printer > Manage. Then select Set as default. If you have Let Windows manage my default printer selected, you’ll need to deselect it before you can choose a default printer on your own.
In Windows 10, your default can be the printer you last used. To turn on this mode, open Start and select Settings > Devices > Printers & scanners. Select the checkbox beside Let Windows manage my default printer.
Taken from Microsoft support
path = os.path.join(pathlib.Path(__file__).parent.absolute(), f.name)
win32api.ShellExecute(
0,
"print",
f.name,
'"%s"' % win32print.GetDefaultPrinter(),
".",
0
)
Marking An Email As Read
In order to mark an email as read, we will use the modify()
methid.
The following function recievce an email ID and the service (the same service we used throught this whole guide) and marks it as read.
def markEmailAsRead(service, message):
service.users().messages().modify(userId='me', id=message['id'], body={'removeLabelIds': ['UNREAD']}).execute()
Pretty simple, right?
If you want to make an email as unread, you can just change removeLabelIds
to addLabelsIds
:
def markEmailAsRead(service, message):
service.users().messages().modify(userId='me', id=message['id'], body={'addLabelIds': ['UNREAD']}).execute()
Conclusion
There is much more you can do using the Gmail API – fetch emails, change emails’ labels, send emails, fetch emails’ attachments.
Basically, you can automate almost everything (and maybe even everything) gmail allows you to do.
You can explore the documentation to see more awesome stuff the API allows you to do. Done anything awesome? Share it here! 😀