fbpx

Using Gmail API

Read Time:8 Minute, 19 Second

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! 😀

Leave a Reply

Your email address will not be published. Required fields are marked *