Skip to main content

pythonbird

PyPI Python Versions License PyPI Downloads

A lightweight, zero-runtime-dependency Python library for working with local Mozilla Thunderbird profiles on Linux.

Current version: 1.0.0

Features

  • Detects standard, Snap, and Flatpak Thunderbird profiles.
  • Supports explicitly selected profiles and offline profile backups.
  • Parses structured Thunderbird accounts, identities, server settings, and legacy email-address lists.
  • Discovers local and cached IMAP Mbox folders, including nested .sbd folders.
  • Provides typed Account, Folder, Message, Attachment, and Contact objects.
  • Searches messages by addresses, subject, content, dates, attachments, flags, and tags.
  • Reads Thunderbird read, starred, replied, forwarded, and tag metadata.
  • Explicit opt-in Mbox writes for read/unread, stars, tags, copy, move, trash, and permanent delete.
  • Saves attachments, EML files, decoded text bodies, and HTML bodies.
  • Exports folders to JSON.
  • Discovers and reads multiple SQLite address books in read-only mode.
  • Searches contacts by name or email address.
  • Opens native Thunderbird compose windows with To, Cc, Bcc, subject, body, and attachment fields.
  • Preserves the public APIs introduced in pythonbird 0.1.x–0.3.x.
  • Ships typing metadata (py.typed) and a Python 3.9–3.12 CI matrix.

Requirements

  • Linux
  • Python 3.9–3.12
  • Mozilla Thunderbird only when opening a compose window

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"],
)

Accounts

accounts() remains the compatibility API and returns email addresses:

print(tb.accounts())

Use structured account objects for new code:

for account in tb.account_objects():
    print(account.id)
    print(account.name)
    print(account.email)
    print(account.identities)
    print(account.server_type)
    print(account.hostname)
    print(account.username)
    print(account.port)

Folders

Canonical folder names use / for nesting:

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

archive = tb.folder("Archive/2026")
for message in archive.messages(limit=20):
    print(message.subject)

folder() returns a typed Folder object with reading, searching, and write helpers.

A unique short folder name is accepted. If several folders have the same short name, use the canonical 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,
    tags=["work", "important"],
    limit=50,
)

For large mailboxes, use the iterator:

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

Explicit write operations

Mbox modification is disabled by default. To modify a profile, opt in explicitly:

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

message = tb.mark_read(message)
message = tb.star(message)
message = tb.add_tags(message, ["work"])
message = tb.move(message, "Archive")

You can also work through a Folder:

inbox = tb.folder("Inbox")
message = inbox.messages(limit=1)[0]
message = inbox.mark_read(message)
message = inbox.set_tags(message, ["important", "later"])

Other operations include copy(), trash(), and delete().

Close Thunderbird before using write operations. pythonbird locks the Mbox through Python's mailbox implementation, but it cannot coordinate Thunderbird's own database/index state while Thunderbird is running. Always keep backups of important profiles. Permanent delete cannot be undone.

Attachments and exports

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

pythonbird discovers compatible local Thunderbird SQLite address books:

for path in tb.address_books():
    print(path)

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

Search across address books:

matches = tb.find_contacts("alice", limit=20)

A specific database can still be supplied with database_path=. Address-book databases are opened read-only.

Compose window

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

The compose process is launched without shell=True. pythonbird intentionally delegates actual sending and authentication to Thunderbird rather than implementing an SMTP credential stack.

Compatibility

The low-level classes remain public:

from pythonbird import ThunderbirdContacts, ThunderbirdLinux, ThunderbirdMail

The dictionary-based mail API from 0.1.x remains available, including get_local_inbox_messages() and iter_mbox_messages().

Scope and limitations

pythonbird 1.0.0 is an API for local Thunderbird profile automation. It does not attempt to replace Thunderbird or implement its network protocols.

  • IMAP content must be cached in the local profile to be readable as Mbox data.
  • Calendar APIs, watchers, direct SMTP sending, and Windows/macOS profile discovery are not part of 1.0.0.
  • Thunderbird metadata headers and .msf indexes can become stale; write operations modify Mbox content but do not directly edit .msf indexes.
  • Close Thunderbird before write operations and back up important profiles.

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

Development

poetry install
poetry run pytest
poetry run black --check pythonbird tests
poetry run flake8 pythonbird tests --max-line-length=88 --extend-ignore=E203,W503
poetry build

GitHub Actions runs tests on Python 3.9, 3.10, 3.11, and 3.12 and validates the distributions before release.

License

MIT. See LICENSE.

Download files

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

Source Distribution

pythonbird-1.0.0.tar.gz (18.6 kB view details)

Uploaded Source

Built Distribution

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

pythonbird-1.0.0-py3-none-any.whl (19.4 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for pythonbird-1.0.0.tar.gz
Algorithm Hash digest
SHA256 38fd33e78d46645323d11bf853b018db11c4a705ff7fbf48ebc03cd71805233a
MD5 cd0aaacc3dd7294b47c5ac5387476ddc
BLAKE2b-256 166ac5434cb23c8698a237a77d0b794e32879dfec46254b361b2cf4d13f2d857

See more details on using hashes here.

Provenance

The following attestation bundles were made for pythonbird-1.0.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-1.0.0-py3-none-any.whl.

File metadata

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

File hashes

Hashes for pythonbird-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 10702e18bbded9f8649801edc825a30601d1bdd052981f97260213a611e58cde
MD5 ead446317634d97cfed56d6004e7ead3
BLAKE2b-256 4d3444bd664b9299b0fca61dd040b4694e3abffc4bc690d0ac6a3ba2fd762fda

See more details on using hashes here.

Provenance

The following attestation bundles were made for pythonbird-1.0.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.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 files

0.3.0

2 files

0.2.2

2 files

0.2.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page