marcboeker/gmail-to-sqlite

Index your Gmail account to a SQLite DB and play with the data.

Python

1,222

51 commits

updated Oct 11, 2026

See the code

README

Gmail to SQLite

Header

A robust Python application that syncs Gmail messages to a local SQLite database for analysis and archival purposes.

Features

  • Incremental Sync: Only downloads new messages by default
  • Full Sync: Option to download all messages and detect deletions
  • Parallel Processing: Multi-threaded message fetching for improved performance
  • Robust Error Handling: Automatic retries with exponential backoff
  • Graceful Shutdown: Handles interruption signals cleanly
  • Type Safety: Comprehensive type hints throughout the codebase

Installation

Prerequisites

  • Python 3.8 or higher
  • Google Cloud Project with Gmail API enabled
  • OAuth 2.0 credentials file (credentials.json)

Setup

  1. Clone the repository:

    git clone https://github.com/marcboeker/gmail-to-sqlite.git
    cd gmail-to-sqlite
    
  2. Install dependencies:

    # Using uv
    uv sync
    
  3. Set up Gmail API credentials:

    • Go to the Google Cloud Console
    • Create a new project or select an existing one
    • Enable the Gmail API
    • Create OAuth 2.0 credentials (Desktop application)
    • Download the credentials file and save it as credentials.json in the project root

Usage

Basic Commands

You can run the application using either python directly or via uv:

# Incremental sync (default)
python main.py sync --data-dir ./data
# or: uv run main.py sync --data-dir ./data

# Full sync with deletion detection
python main.py sync --data-dir ./data --full-sync

# Sync a specific message
python main.py sync-message --data-dir ./data --message-id MESSAGE_ID

# Detect and mark deleted messages only
python main.py sync-deleted-messages --data-dir ./data

# Use custom number of worker threads
python main.py sync --data-dir ./data --workers 8

# Get help
python main.py --help
python main.py sync --help

Command Line Arguments

  • command: Required. One of sync, sync-message, or sync-deleted-messages
  • --data-dir: Required. Directory where the SQLite database will be stored
  • --full-sync: Optional. Forces a complete sync of all messages
  • --message-id: Required for sync-message. The ID of a specific message to sync
  • --workers: Optional. Number of worker threads (default: number of CPU cores)
  • --help: Show help information for commands and options

Graceful Shutdown

The application supports graceful shutdown when you press CTRL+C:

  1. Stops accepting new tasks
  2. Waits for currently running tasks to complete
  3. Saves progress of completed work
  4. Exits cleanly

Pressing CTRL+C a second time will force an immediate exit.

Database Schema

The application creates a SQLite database with the following schema:

FieldTypeDescription
message_idTEXTUnique Gmail message ID
thread_idTEXTGmail thread ID
senderJSONSender information (name, email)
recipientsJSONRecipients by type (to, cc, bcc)
labelsJSONArray of Gmail labels
subjectTEXTMessage subject
bodyTEXTMessage body (plain text)
sizeINTEGERMessage size in bytes
timestampDATETIMEMessage timestamp
is_readBOOLEANRead status
is_outgoingBOOLEANWhether sent by user
is_deletedBOOLEANWhether deleted from Gmail
last_indexedDATETIMELast sync timestamp

Example queries

Get the number of emails per sender

SELECT sender->>'$.email', COUNT(*) AS count
FROM messages
GROUP BY sender->>'$.email'
ORDER BY count DESC

Show the number of unread emails by sender

This is great to determine who is spamming you the most with uninteresting emails.

SELECT sender->>'$.email', COUNT(*) AS count
FROM messages
WHERE is_read = 0
GROUP BY sender->>'$.email'
ORDER BY count DESC

Get the number of emails for a specific period

  • For years: strftime('%Y', timestamp)
  • For months in a year: strftime('%m', timestamp)
  • For days in a month: strftime('%d', timestamp)
  • For weekdays: strftime('%w', timestamp)
  • For hours in a day: strftime('%H', timestamp)
SELECT strftime('%Y', timestamp) AS period, COUNT(*) AS count
FROM messages
GROUP BY period
ORDER BY count DESC

Find all newsletters and group them by sender

This is an amateurish way to find all newsletters and group them by sender. It's not perfect, but it's a start. You could also use

SELECT sender->>'$.email', COUNT(*) AS count
FROM messages
WHERE body LIKE '%newsletter%' OR body LIKE '%unsubscribe%'
GROUP BY sender->>'$.email'
ORDER BY count DESC

Show who has sent the largest emails in MB

SELECT sender->>'$.email', sum(size)/1024/1024 AS size
FROM messages
GROUP BY sender->>'$.email'
ORDER BY size DESC

Count the number of emails that I have sent to myself

SELECT count(*)
FROM messages
WHERE EXISTS (
  SELECT 1
  FROM json_each(messages.recipients->'$.to')
  WHERE json_extract(value, '$.email') = 'foo@example.com'
)
AND sender->>'$.email' = 'foo@example.com'

List the senders who have sent me the largest total volume of emails in megabytes

SELECT sender->>'$.email', sum(size)/1024/1024 as total_size
FROM messages
WHERE is_outgoing=false
GROUP BY sender->>'$.email'
ORDER BY total_size DESC

Find all deleted messages

SELECT message_id, subject, timestamp
FROM messages
WHERE is_deleted=1
ORDER BY timestamp DESC

marcboeker/gmail-to-sqlite

Index your Gmail account to a SQLite DB and play with the data.

Python

1,222

51 commits

updated Oct 11, 2026

See the code

README

Gmail to SQLite

Header

A robust Python application that syncs Gmail messages to a local SQLite database for analysis and archival purposes.

Features

  • Incremental Sync: Only downloads new messages by default
  • Full Sync: Option to download all messages and detect deletions
  • Parallel Processing: Multi-threaded message fetching for improved performance
  • Robust Error Handling: Automatic retries with exponential backoff
  • Graceful Shutdown: Handles interruption signals cleanly
  • Type Safety: Comprehensive type hints throughout the codebase

Installation

Prerequisites

  • Python 3.8 or higher
  • Google Cloud Project with Gmail API enabled
  • OAuth 2.0 credentials file (credentials.json)

Setup

  1. Clone the repository:

    git clone https://github.com/marcboeker/gmail-to-sqlite.git
    cd gmail-to-sqlite
    
  2. Install dependencies:

    # Using uv
    uv sync
    
  3. Set up Gmail API credentials:

    • Go to the Google Cloud Console
    • Create a new project or select an existing one
    • Enable the Gmail API
    • Create OAuth 2.0 credentials (Desktop application)
    • Download the credentials file and save it as credentials.json in the project root

Usage

Basic Commands

You can run the application using either python directly or via uv:

# Incremental sync (default)
python main.py sync --data-dir ./data
# or: uv run main.py sync --data-dir ./data

# Full sync with deletion detection
python main.py sync --data-dir ./data --full-sync

# Sync a specific message
python main.py sync-message --data-dir ./data --message-id MESSAGE_ID

# Detect and mark deleted messages only
python main.py sync-deleted-messages --data-dir ./data

# Use custom number of worker threads
python main.py sync --data-dir ./data --workers 8

# Get help
python main.py --help
python main.py sync --help

Command Line Arguments

  • command: Required. One of sync, sync-message, or sync-deleted-messages
  • --data-dir: Required. Directory where the SQLite database will be stored
  • --full-sync: Optional. Forces a complete sync of all messages
  • --message-id: Required for sync-message. The ID of a specific message to sync
  • --workers: Optional. Number of worker threads (default: number of CPU cores)
  • --help: Show help information for commands and options

Graceful Shutdown

The application supports graceful shutdown when you press CTRL+C:

  1. Stops accepting new tasks
  2. Waits for currently running tasks to complete
  3. Saves progress of completed work
  4. Exits cleanly

Pressing CTRL+C a second time will force an immediate exit.

Database Schema

The application creates a SQLite database with the following schema:

FieldTypeDescription
message_idTEXTUnique Gmail message ID
thread_idTEXTGmail thread ID
senderJSONSender information (name, email)
recipientsJSONRecipients by type (to, cc, bcc)
labelsJSONArray of Gmail labels
subjectTEXTMessage subject
bodyTEXTMessage body (plain text)
sizeINTEGERMessage size in bytes
timestampDATETIMEMessage timestamp
is_readBOOLEANRead status
is_outgoingBOOLEANWhether sent by user
is_deletedBOOLEANWhether deleted from Gmail
last_indexedDATETIMELast sync timestamp

Example queries

Get the number of emails per sender

SELECT sender->>'$.email', COUNT(*) AS count
FROM messages
GROUP BY sender->>'$.email'
ORDER BY count DESC

Show the number of unread emails by sender

This is great to determine who is spamming you the most with uninteresting emails.

SELECT sender->>'$.email', COUNT(*) AS count
FROM messages
WHERE is_read = 0
GROUP BY sender->>'$.email'
ORDER BY count DESC

Get the number of emails for a specific period

  • For years: strftime('%Y', timestamp)
  • For months in a year: strftime('%m', timestamp)
  • For days in a month: strftime('%d', timestamp)
  • For weekdays: strftime('%w', timestamp)
  • For hours in a day: strftime('%H', timestamp)
SELECT strftime('%Y', timestamp) AS period, COUNT(*) AS count
FROM messages
GROUP BY period
ORDER BY count DESC

Find all newsletters and group them by sender

This is an amateurish way to find all newsletters and group them by sender. It's not perfect, but it's a start. You could also use

SELECT sender->>'$.email', COUNT(*) AS count
FROM messages
WHERE body LIKE '%newsletter%' OR body LIKE '%unsubscribe%'
GROUP BY sender->>'$.email'
ORDER BY count DESC

Show who has sent the largest emails in MB

SELECT sender->>'$.email', sum(size)/1024/1024 AS size
FROM messages
GROUP BY sender->>'$.email'
ORDER BY size DESC

Count the number of emails that I have sent to myself

SELECT count(*)
FROM messages
WHERE EXISTS (
  SELECT 1
  FROM json_each(messages.recipients->'$.to')
  WHERE json_extract(value, '$.email') = 'foo@example.com'
)
AND sender->>'$.email' = 'foo@example.com'

List the senders who have sent me the largest total volume of emails in megabytes

SELECT sender->>'$.email', sum(size)/1024/1024 as total_size
FROM messages
WHERE is_outgoing=false
GROUP BY sender->>'$.email'
ORDER BY total_size DESC

Find all deleted messages

SELECT message_id, subject, timestamp
FROM messages
WHERE is_deleted=1
ORDER BY timestamp DESC

Significant stargazers

Hiroshi SHIBATA

1,672 followers · starred May 2025

Bret Comnes

715 followers · starred May 2025

Bruno P. Kinoshita

387 followers · starred May 2025

utzcoz

135 followers · starred May 2025