pythonbird
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
.sbdfolders. - Provides typed
Account,Folder,Message,Attachment, andContactobjects. - 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
.msfindexes can become stale; write operations modify Mbox content but do not directly edit.msfindexes. - 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
38fd33e78d46645323d11bf853b018db11c4a705ff7fbf48ebc03cd71805233a
|
|
| MD5 |
cd0aaacc3dd7294b47c5ac5387476ddc
|
|
| BLAKE2b-256 |
166ac5434cb23c8698a237a77d0b794e32879dfec46254b361b2cf4d13f2d857
|
Provenance
The following attestation bundles were made for pythonbird-1.0.0.tar.gz:
Publisher:
publish.yml on rchbld/pythonbird
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pythonbird-1.0.0.tar.gz -
Subject digest:
38fd33e78d46645323d11bf853b018db11c4a705ff7fbf48ebc03cd71805233a - Sigstore transparency entry: 2613872637
- Sigstore integration time:
-
Permalink:
rchbld/pythonbird@b992706469108d4c030188a69af98a31636435e7 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/rchbld
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b992706469108d4c030188a69af98a31636435e7 -
Trigger Event:
release
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
10702e18bbded9f8649801edc825a30601d1bdd052981f97260213a611e58cde
|
|
| MD5 |
ead446317634d97cfed56d6004e7ead3
|
|
| BLAKE2b-256 |
4d3444bd664b9299b0fca61dd040b4694e3abffc4bc690d0ac6a3ba2fd762fda
|
Provenance
The following attestation bundles were made for pythonbird-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on rchbld/pythonbird
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pythonbird-1.0.0-py3-none-any.whl -
Subject digest:
10702e18bbded9f8649801edc825a30601d1bdd052981f97260213a611e58cde - Sigstore transparency entry: 2613872902
- Sigstore integration time:
-
Permalink:
rchbld/pythonbird@b992706469108d4c030188a69af98a31636435e7 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/rchbld
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b992706469108d4c030188a69af98a31636435e7 -
Trigger Event:
release
-
Statement type: