Automate Your Inbox: Python Script to Organize Gmail with the API

Automate Your Inbox: Python Script to Organize Gmail with the API

Automate Your Inbox: Python Script to Organize Gmail with the API

 

Is your inbox overflowing with updates, promotions, and unimportant emails? With a little Python and the Gmail API, you can automate email organization tasks like applying labels, archiving, or forwarding messages based on specific criteria. In this guide, we’ll walk through building a real Python script to organize your inbox so you can focus on what matters.

1. Setting Up Access: Gmail API and OAuth 2.0

To access your Gmail inbox using Python, we first need to enable the Gmail API and authorize our script using OAuth 2.0.

Steps:

  1. Go to the Google Cloud Console and create a new project.
  2. Enable the Gmail API under APIs & Services.
  3. Under “Credentials”, create an OAuth 2.0 Client ID for a Desktop application.
  4. Download the credentials.json file to your working directory.

Install the necessary libraries:

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

Authenticate and build a service object:

from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
import os.path

SCOPES = ['https://www.googleapis.com/auth/gmail.modify']

def get_gmail_service():
    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())
    return build('gmail', 'v1', credentials=creds)

2. Fetching Emails Programmatically

Once authenticated, you can now retrieve emails based on criteria like unread status, sender, or keywords. Gmail uses a powerful query syntax similar to what you use in the search bar.

def list_messages(service, query='is:unread'):    
    results = service.users().messages().list(userId='me', q=query).execute()
    messages = results.get('messages', [])
    return messages

service = get_gmail_service()
unread_messages = list_messages(service, 'is:unread label:inbox')
print(f"Found {len(unread_messages)} unread emails")

Tip: You can also filter by from:, subject:, has:attachment, or time (e.g., newer_than:2d).

3. Applying Labels, Archiving or Forwarding

Now let’s automate some basic actions depending on email content. For example, label all GitHub notification emails or move them to Archives.

def modify_email(service, msg_id, add_labels=[], remove_labels=[]):
    msg_labels = {'addLabelIds': add_labels, 'removeLabelIds': remove_labels}
    service.users().messages().modify(userId='me', id=msg_id, body=msg_labels).execute()

Example: Archive a message

for msg in unread_messages:
    msg_id = msg['id']
    modify_email(service, msg_id, remove_labels=['INBOX'])

Example: Add a ‘GitHub’ label

def get_label_id(service, label_name):
    labels = service.users().labels().list(userId='me').execute().get('labels', [])
    for label in labels:
        if label['name'] == label_name:
            return label['id']
    return None

label_id = get_label_id(service, 'GitHub')
for msg in unread_messages:
    message = service.users().messages().get(userId='me', id=msg['id']).execute()
    if 'github.com' in str(message.get('snippet', '')).lower():
        modify_email(service, msg['id'], add_labels=[label_id], remove_labels=['INBOX'])

4. Putting It All Together: Rule-Based Automation Engine

Let’s now generalize the above into a simple rule engine. You can define rules in a list and let the script process them one by one.

rules = [
    {
        'query': 'from:noreply@github.com is:unread',
        'label': 'GitHub',
        'archive': True
    },
    {
        'query': 'from:newsletter@producthunt.com newest',
        'label': 'Newsletters',
        'archive': False
    }
]

for rule in rules:
    messages = list_messages(service, rule['query'])
    label_id = get_label_id(service, rule['label'])
    for msg in messages:
        modify_email(service, msg['id'],
                     add_labels=[label_id] if label_id else [],
                     remove_labels=['INBOX'] if rule['archive'] else [])

This modular approach allows you to easily extend or modify rules without editing core logic.

5. Optimization and Going Beyond

Performance Tips:

  • Use batch requests (with batch_http_request) when processing large amounts of messages.
  • Cache label IDs to avoid repeated API requests.
  • Log actions to a local file or database to track automation activity.

Going further:

  • Automatically forward invoices to your accounting system.
  • Set up reminders for unread emails after 3 days.
  • Integrate with Slack to notify you of urgent emails.

Here’s a batch labeling example with simple batching logic:

from googleapiclient.http import BatchHttpRequest

def process_in_batch(service, message_ids, label_ids):
    def callback(request_id, response, exception):
        if exception:
            print(f"Error for message {request_id}: {exception}")
        else:
            print(f"Successfully updated message {request_id}")

    batch = BatchHttpRequest(callback=callback)
    for msg_id in message_ids:
        batch.add(service.users().messages().modify(userId='me', id=msg_id,
                                                    body={'addLabelIds': label_ids}))
    batch.execute()

Conclusion

Automating your inbox can drastically reduce repetitive tasks and help you stay focused on critical messages. With the Gmail API and Python, applying custom rules is not only powerful but also fun once scripted. Whether labeling GitHub notifications or archiving daily newsletters, you’re now equipped to build a smarter inbox.

Happy scripting!

 

Useful links: