Gmail message count insights with Python

This Python script makes use of the Gmail API to efficiently analyze your inbox.

It retrieves the total number of emails and conversations, categorizes them by system and user-defined labels, and displays the count of emails under each label.

This script offers you insights into email usage patterns, label hierarchies, and the volume of communication within specific categories.


To run the script successfully, you will need the following prerequisites:

  1. Create a new Google Project
  2. Enable the Drive API
  3. Create an OAuth consent screen
  4. Create OAuth 2.0 Client IDs – Desktop App
  5. Download the JSON file
  6. Setup Python
    $ sudo apt install python3-pip
    $ pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib

Further information can be found in the Python quickstart guide from Google.

In order to run the script, simply rename the JSON file you’ve downloaded to “credentials.json“, position it within the script’s directory.


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

# Define the Google Drive API scopes for accessing files and folders
# If modifying these scopes, delete the file token.json
SCOPES = ['']
TOKEN_PATH = 'token.json'
CREDENTIALS_PATH = 'credentials.json'

def get_credentials():
    # Gets user credentials or prompts for authorization if needed
    # Try to load existing credentials from 'token.json'
    creds = Credentials.from_authorized_user_file(TOKEN_PATH, SCOPES) if os.path.exists(TOKEN_PATH) else None

    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            # Refresh the credentials if they are expired and can be refreshed
            # If no valid credentials exist, initiate the OAuth flow to obtain them
            flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS_PATH, SCOPES)
            creds = flow.run_local_server(port=0)

        # Save the obtained credentials for future runs
        with open(TOKEN_PATH, 'w') as token_file:

    return creds

def get_label_info(service, label_id):
    # Fetch label information for a given label ID
    label_info = service.users().labels().get(userId='me', id=label_id).execute()
    return label_info

def print_label_tree(labels, label_type, service):
    # Print label information in a hierarchical tree structure
    sorted_labels = sorted(labels, key=lambda x: x['name'].lower())
    for label in sorted_labels:
        label_info = get_label_info(service, label['id'])
        total_emails = label_info.get('messagesTotal', 0)
        print(f"- {label['name']} - [{total_emails}]")

def count_emails_by_label_type():
    # Count and display emails grouped by label type
    creds = get_credentials()
    service = build('gmail', 'v1', credentials=creds)
    profile = service.users().getProfile(userId='me').execute()

    if 'emailAddress' in profile:
        email_address = profile['emailAddress']
        print(f"Email Address: {email_address}")

        total_emails = profile['messagesTotal']
        total_conversations = profile['threadsTotal']

        print(f"Total Emails: {total_emails}")
        print(f"Total Conversations: {total_conversations}")

        labels_response = service.users().labels().list(userId='me').execute()
        all_labels = labels_response.get('labels', [])

        # Group labels into system and user-defined categories
        system_labels = [label for label in all_labels if label.get('type') == 'system']
        user_labels = [label for label in all_labels if label.get('type') == 'user']

        # Print system and user labels with their respective email counts
        print_label_tree(system_labels, "System Labels\n", service)
        print_label_tree(user_labels, "User Labels\n", service)
        print("Email address not found in the profile.")

if __name__ == '__main__':
asterix Written by:

Be First to Comment

Leave a Reply

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