Metadata-Version: 2.4
Name: pythonbird
Version: 1.0.0
Summary: A Python library for local Mozilla Thunderbird profiles, mailboxes, accounts, address books, and native compose windows on Linux.
License: MIT
License-File: LICENSE
Keywords: thunderbird,email,mbox,sqlite,linux,automation
Author: rchbld
Author-email: diamondhead650@gmail.com
Requires-Python: >=3.9,<4.0
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Communications :: Email
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Project-URL: Repository, https://github.com/rchbld/pythonbird
Description-Content-Type: text/markdown

# pythonbird

[![PyPI](https://img.shields.io/pypi/v/pythonbird)](https://pypi.org/project/pythonbird/)
[![Python Versions](https://img.shields.io/pypi/pyversions/pythonbird)](https://pypi.org/project/pythonbird/)
[![License](https://img.shields.io/github/license/rchbld/pythonbird)](LICENSE)
[![PyPI Downloads](https://img.shields.io/pypi/dm/pythonbird)](https://pypi.org/project/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 `.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

```bash
pip install pythonbird
```

or:

```bash
poetry add pythonbird
```

## Quick start

```python
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:

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

## Accounts

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

```python
print(tb.accounts())
```

Use structured account objects for new code:

```python
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:

```python
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

```python
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:

```python
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:

```python
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`:

```python
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

```python
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:

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

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

Search across address books:

```python
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

```python
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:

```python
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](GUIDE.md) for the complete API reference and [CHANGELOG.md](CHANGELOG.md) for release history.

## Development

```bash
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](LICENSE).

