Skip to main content

A Python library to interact with local Mozilla Thunderbird profiles and mail client data on Linux.

Project description

pythonbird

PyPI Python Versions License PyPI Downloads

A lightweight, zero-dependency Python library for reading local Mozilla Thunderbird profiles, mailboxes, address books, and opening native compose windows on Linux.

Current version: 0.3.0

Features

  • Detects standard, Snap, and Flatpak Thunderbird profiles.
  • Supports explicitly selected or backed-up profile directories.
  • Reads configured accounts from prefs.js.
  • Discovers local and IMAP Mbox folders, including nested .sbd folders.
  • Returns typed Message, Attachment, and Contact objects.
  • Searches by addresses, subject, content, dates, attachments, flags, and tags.
  • Reads Thunderbird read, starred, replied, and forwarded status metadata.
  • Reads Thunderbird tags from X-Mozilla-Keys.
  • Saves attachments, EML files, decoded text bodies, and HTML bodies.
  • Exports folders to JSON.
  • Reads SQLite address books in read-only mode.
  • Opens Thunderbird compose windows without using a system shell.
  • Preserves the dictionary-based API from pythonbird 0.1.x.

Requirements

  • Linux
  • Python 3.9 or newer
  • Mozilla Thunderbird only when opening compose windows

Reading an explicitly supplied profile or backup does not require Thunderbird to be installed.

Installation

pip install pythonbird

or:

poetry add pythonbird

Quick start

from pythonbird import Thunderbird, __version__

print(__version__)

tb = Thunderbird()

print(tb.profile_dir)
print(tb.accounts())
print(tb.folders())

for message in tb.messages("Inbox", limit=20):
    print(message.subject, message.sender, message.read)

Use an explicit profile when automatic detection is not appropriate:

tb = Thunderbird(
    profile_dir="/home/user/.thunderbird/example.default-release",
    command=["thunderbird"],
)

Folders

Canonical folder names use / for nesting:

for folder in tb.folders():
    print(folder)

messages = tb.messages("Archive/2026")

A unique short folder name is accepted. When several folders have the same short name, use the full name returned by folders().

Searching messages

from datetime import date

results = tb.search(
    "Inbox",
    sender="github.com",
    recipient="example.com",
    subject="report",
    contains="release",
    after=date(2026, 1, 1),
    before=date(2026, 12, 31),
    has_attachments=True,
    unread=True,
    starred=True,
    replied=False,
    forwarded=False,
    tags=["work", "important"],
    limit=50,
)

For large mailboxes, use the iterator:

for message in tb.iter_search("Inbox", unread=True):
    print(message.subject)

Tag matching is case-insensitive and all requested tags must be present. Messages without a valid Thunderbird status do not match unread=True or unread=False.

Message metadata

message = tb.messages("Inbox", limit=1)[0]

print(message.sender)
print(message.recipients)
print(message.subject)
print(message.date)
print(message.text_body)
print(message.html_body)
print(message.read)       # True, False, or None when status is unavailable
print(message.starred)
print(message.replied)
print(message.forwarded)
print(message.tags)

Status and tag support is read-only. Version 0.3.0 does not modify Mbox files or Thunderbird indexes.

Attachments and export

message.save_attachments("downloads")
message.save_eml("exports/message.eml")
message.save_text("exports/message.txt")
message.save_html("exports/message.html")

tb.export_json("exports/inbox.json", folder="Inbox", limit=100)

Existing files are not overwritten unless overwrite=True is explicitly passed to a model save method.

Contacts

for contact in tb.contacts():
    print(contact.name, contact.email)

Read a different Thunderbird address book:

contacts = tb.contacts(
    database_path="/path/to/address-book.sqlite",
    strict=True,
)

With strict=False, SQLite and schema errors produce an empty list instead of raising ThunderbirdContactsError.

Compose window

tb.compose(
    to="developer@example.com",
    subject="Created with pythonbird",
    body="Hello from pythonbird!",
    attachment_path="/path/to/report.pdf",
)

The compose window is opened through an argument list without shell=True. The attachment must exist.

Low-level and legacy APIs

The public low-level classes remain available:

from pythonbird import ThunderbirdContacts, ThunderbirdLinux, ThunderbirdMail

client = ThunderbirdLinux()
mail = ThunderbirdMail(client)
contacts = ThunderbirdContacts(client)

The 0.1.x dictionary API is preserved:

messages = mail.get_local_inbox_messages(limit=20)

for message in mail.iter_mbox_messages("/path/to/mbox"):
    print(message["subject"])

Safety and limitations

  • pythonbird 0.3.0 reads mail and address-book data but does not change Mbox files.
  • Thunderbird metadata headers may be absent or stale; read is therefore optional.
  • IMAP folders must be present in the local Thunderbird profile to be readable.
  • Calendar, SMTP sending, watchers, and Windows/macOS profile support are not included.
  • Work with a backup when inspecting important profiles from custom scripts.

See GUIDE.md for the complete API reference and CHANGELOG.md for release history.

Development

poetry install
poetry run pytest
poetry run black --check .
poetry run flake8 pythonbird tests
poetry build

License

MIT. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pythonbird-0.3.0.tar.gz (13.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pythonbird-0.3.0-py3-none-any.whl (14.7 kB view details)

Uploaded Python 3

File details

Details for the file pythonbird-0.3.0.tar.gz.

File metadata

  • Download URL: pythonbird-0.3.0.tar.gz
  • Upload date:
  • Size: 13.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for pythonbird-0.3.0.tar.gz
Algorithm Hash digest
SHA256 d580046a5a9694335e2f19f065ee3afc7c6c28960e7937821d2eedd6647813f2
MD5 d1f33a83618c2ba45aa0c2450bedb8af
BLAKE2b-256 42fabde922a510709fc2c7c8ee8ebf5705f55b46d6e3cd038c3dd72ea2cb8fbd

See more details on using hashes here.

Provenance

The following attestation bundles were made for pythonbird-0.3.0.tar.gz:

Publisher: publish.yml on rchbld/pythonbird

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pythonbird-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: pythonbird-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 14.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for pythonbird-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 681b3613d4708c3e3b5df2b735431c3052a36d9a47ada01eb581c8ea7d35dc5d
MD5 05e9ea319b5bce9efd3b0cbd8fdda516
BLAKE2b-256 2b0ab23de7ce16bda83e7ec39b961cfa32cb4636864e07d1fdb91282a17dc5b6

See more details on using hashes here.

Provenance

The following attestation bundles were made for pythonbird-0.3.0-py3-none-any.whl:

Publisher: publish.yml on rchbld/pythonbird

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page