CodeTops - gmail api

How to get started with Gmail API

Part 1 - Create New project

console.cloud.google -(google cloud platform)

01

 Go to the console.cloud google and create a new project
https://developers.google.com/gmail/api/guides

 Create a new project name mygmaildata

02

 Select the project go to Library or Enable APIs & Services, search for gmail api, and ENABLE it.

03

Enable The Gmail API

04

Go to CREATE CREDENTIALS in the api.

05

You might also be able to do it on the Credential pages

Part 2 - Create Credentials - Credential Type & Scopes

Credential types and Scopes

01

Choose User Data then hit NEXT

02

Name and enter emails, then hit

03

click ADD OR REMOVE SCOPES and filter gmail to see the available scopes

04

For now, choose the readonly scope and click update

05

The scope will appear at the bottom of the page, Click SAVE and Continue

06

Choose Desktop App for OAuth type, and name it

07

Download the client_secret file to same directory as the script

Part 3 - OAuth Client ID - Applicaiton Type* -Desktop App

01

Select Desktop App for Applicaion Type* and give the same name as the console.cloud.google project name then click CREATE

02

This is also stated in the Gmail Api Documentation -> QuickstartsPython

03

Download the the credentials to the same directory as the project, then click DONE

Part 4 add Test user

01

Go to OAuth consent screen to add ADD USERS and add your email to the User

04

Enter the email you wish to use

Part 5 Create a VENV & Install Libraries

01

Go to jieJenn 00-GetStartGmailApi-Python for review, and install a venv in the directory of the project, and install the libraries

python -m venv venv
./venv/bin/activate

02

If ./venv/bin/activate Does Not Work run

source ./venv/bin/activate

03

Go to https://developers.google.com/gmail/api/quickstart/python , and install the client libraries

pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib

04

To deactivate and exit the venv type,

deactivate

Part 6 - Gmail Api -> Quickstarts -> python -> (token.json)

01

To get started quick copy and paste the code into your script from the Gmail Api -> Quickstarts -> python page
https://developers.google.com/gmail/api/quickstart/python

02

 Make sure you change the name of credentials.json to your client_secret file name, and Keep creds = to None

import os.path

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

# If modifying these scopes, delete the file token.json.
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.json 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.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:
    # Call the Gmail API
    service = build("gmail", "v1", credentials=creds)
    results = service.users().labels().list(userId="me").execute()
    labels = results.get("labels", [])

    if not labels:
      print("No labels found.")
      return
    print("Labels:")
    for label in labels:
      print(label["name"])

  except HttpError as error:
    # TODO(developer) - Handle errors from gmail API.
    print(f"An error occurred: {error}")


if __name__ == "__main__":
  main()

03

Run the python script and the browser will open to this page showing gmail accounts, **Only test users assigned in part 4 - add Test user

04

Click Continue

05

Click Continue

06

When you see this page, you can now use the data in your script

07

A token.json will be downloaded into the same directory as the script

Part 7 - Project - Python Code get token.json - ( step 1 )

01

Fix tabindexes for images only step-col & and img-4-container img sizes

Import the client libraies and add the scope

import os.path
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.readonly"]

02

(this code doesn't not work alone)

 Write the function myEmails()
1. First, check if os.path exist between script and api, And, if there is a token.json (which right now there is no token.json ) **this code will do nothing

creds's value will be assigned a Credentials object with a from_authorized_user_file method and token.json and SCOPES as arguments.

import os.path
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.readonly"]

def myEmails():
  creds = None
  if os.path.exists('token.json'):
    creds = Credentials.from_authorized_user_file('token.js',SCOPES)

03

(this code doesn't not work alone)

 The next conditional checks if creds does not and if creds is not valid.
If So,
 the nested condition checks if creds exist, expired, and for a refresh_token which will be in the token.json, and refreshes creds with a Request() function in the refresh method

 Otherwise if everything exists, the else statement assignes the InstallAppFlow class with the from_client_secrets_file method to flow (this makes the request)

 and assigns flow with a run_local_server method with port=0 to creds

import os.path
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.readonly"]

def myEmails():
    creds = None
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json',SCOPES)
    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('client_secret.json',SCOPES)
        creds = flow.run_local_server(port=0 )

04

Working code

(This will not work if token.js already exists)

Write the creds to a file called token.js, The first time the script runs, the token.json file will be created. Therefore after that, we can use the data from the api

Run the script and the browser will open with emails ( ** Remember ) you can only use emails assigned as Test Users as seen in part 4

import os.path
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.readonly"]

def myEmails():
    creds = None
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
    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)
            cred = flow.run_local_server(port=0)
        with open ('token.json ','w') as token:
            token.write(creds.to_json())
myEmails()

05

Select the email and hit continues on each page, until the page tells you can close the window.

Fix these images

06

The token.js file will appear in the same directory as the script

Part 8 - Python Code - service = build('gmail','v1',Credentials=creds) - (step 2)

01

The build function from googleapiclient.discovery will check if creds exists, and connect to the api, here we can print out the first message

Go to https://developers.google.com/gmail/api/reference/rest for more details on users(),messages(),list() and the get() function

import os.path
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.readonly"]

def myEmails():
    creds = None
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
    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)
            cred = flow.run_local_server(port=0)
        with open ('token.json ','w') as token:
            token.write(creds.to_json())
    try:
        service = build('gmail','v1',credentials=creds)
        result = service.users().messages().list(userId='me').execute()
        messages = result.get('messages')
        print(messages[0])
    except HttpError as error:
        print('err',error)

myEmails()

02

Within try: we can loop through the messages

try:
    service = build('gmail','v1',credentials=creds)
    result = service.users().messages().list(userId='me').execute()
    messages = result.get('messages')
    for i in messages:
        print(i)
except HttpError as error:
    print('err',error)

03

As we are loopin throught the messages, we can use the 'id''s in the get() function to retrieve the payload,
Figure out what a payload means

try:
    service = build('gmail','v1',credentials=creds)
    result = service.users().messages().list(userId='me').execute()
    messages = result.get('messages')
    for i in messages:
        txt = service.users().messages().get(userId='me',id=i['id']).execute()
        payload = txt['payload']
        print(payload)
except HttpError as error:
    print('err',error)

You can see at the bottom of the video the console in vs code, printing all the contents of the payload

04

The 'payload' contains the headers which contains the 'subjects' and 'senders' for each messages in gmail.

try:
    service = build('gmail','v1',credentials=creds)
    result = service.users().messages().list(userId='me').execute()
    messages = result.get('messages')
    for i in messages:
        txt = service.users().messages().get(userId='me',id=i['id']).execute()
        payload = txt['payload']
        headers = payload['headers']
        print(headers)
except HttpError as error:
    print('err',error)

This shows the content in headers being printed out

05

We can query the 'headers' and search for the attribute 'name' to find email's 'senders' 'From' and 'subjects' 'Subject to get their 'value'

06

Create 3 empty list to add to for

  • subject
  • senders
  • body

and add to the list for each loop

subjects = []
senders = []
body = []                       

07

Loop through 'headers' and Query with a conditional and search for name for 'Subject', append to subjects and From, append to senders

try:
    service = build('gmail','v1',credentials=creds)
    result = service.users().messages().list(userId='me').execute()
    messages = result.get('messages')
    for i in messages:
        txt = service.users().messages().get(userId='me',id=i['id']).execute()
        payload = txt['payload'] 
        headers = payload['headers']
        for i in headers:
            if i['name'] == 'Subject':
                subjects.append(i['value'])
            if i ['name'] == 'From':
                senders.append(i['value'])
    print(subjects[0])
    print(senders[0])

08

The body of the email is the email itself, It is located in parts which is located back in payload

try:
    service = build('gmail','v1',credentials=creds)
    result = service.users().messages().list(userId='me').execute()
    messages = result.get('messages')
    for i in messages:
        txt = service.users().messages().get(userId='me',id=i['id']).execute()
        payload = txt.get('payload')
        headers = payload.get('headers')
        for i in headers:
            if i['name'] == 'Subject':
                subjects.append(i['value'])
            if i['name'] == 'From':
                senders.append(i['value'])
        parts = payload.get('parts')
        print(parts)

The parts is very long because it contains the email, if you scroll up you can see the 'body with the data attribute which contains the email content.

10

** This code will cause an error because empty messages with have a Nonetype We must replact and Decode the body.'data' attribute, using the library base64 seen at the top of script. import base64

try:
    service = build('gmail','v1',credentials=creds)
    result = service.users().messages().list(userId='me').execute()
    messages = result.get('messages')
    for i in messages:
        txt = service.users().messages().get(userId='me',id=i['id']).execute()
        payload = txt['payload']
        headers = payload['headers']
        for i in headers:
            if i['name'] == 'Subject':
                subjects.append(i['value'])
            if i['name'] == 'From':
                senders.append(i['value'])
        parts = payload.get('parts')[0]
        data = parts['body']['data']
        data = data.replace('-','+').replace('_','/')
        decode_data = base64.b64decode(data)
        body.append(decode_data)
        
        print(data)    
            

10

Check for a none type, and here is the full code

This code doesn't work entirely you can print each message but, if none it breaks

Move on to jieJenn to find new approach, jieJenn-01-gettingStarted

    import os.path
    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
    import base64
    import email
    
    SCOPES = ["https://www.googleapis.com/auth/gmail.readonly"]
    subjects = []
    senders = []
    body = []
    
    def myEmails():
        creds = None
        if os.path.exists('token.json'):
            creds = Credentials.from_authorized_user_file('token.json', SCOPES)
        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.json', 'w') as token:
                token.write(creds.to_json())
    
        try:
            service = build('gmail', 'v1', credentials=creds)
            result = service.users().messages().list(userId='me').execute()
            messages = result.get('messages')
            for i in messages:
                txt = service.users().messages().get(userId='me', id=i['id']).execute()
                payload = txt['payload']
                headers = payload['headers']
                for i in headers:
                    if i['name'] == 'Subject':
                        subjects.append(i['value'])
                    if i['name'] == 'From':
                        senders.append(i['value'])
                parts = payload.get('parts')
                if parts:
                    parts = parts[0]
                    data = parts['body']['data']
                    data = data.replace('-', '+').replace('_', '/')
                    decode_data = base64.b64decode(data)
                    print(decode_data)
                    body.append(decode_data)

        if body:
            print(body[0].decode('utf-8'))  # Decode the bytes to string
            # print(body[2])  # Decode the bytes to string
    
        except HttpError as error:
            print('err', error)
    
    myEmails()