Mailbox manages mailing lists and related information for The Flip pinball museum. It is a Python application built on the Kit (kit.com) v4 API, where mailing lists, subscribers, tags, sequences, and broadcasts are composed and sent.
It is a sibling of flipfix (the museum's maintenance-tracking app) and deliberately mirrors its tooling and conventions.
- Python 3.14+
uvfor dependency and environment management
make bootstrapThis syncs dependencies with uv, installs pre-commit hooks, and creates .env from .env.example. Then add your Kit API key to .env:
# .env
KIT_API_KEY=your-v4-api-keyCreate a V4 API key in your Kit account under Settings → Developer. See docs/KitAPI.md.
make test # Fast test suite (no live API calls)
make quality # Format, lint, typecheck
make test-all # Full suite including @integration tests (needs a real key + network)Mailbox ships a mailbox command. make bootstrap (or uv sync) installs it into
the project venv, so uv run mailbox … works immediately. To type plain mailbox
from anywhere, install it on your PATH:
uv tool install --editable . # adds `mailbox` to ~/.local/bin (editable: tracks the source)After that, mailbox works from any directory (it still reads this project's .env).
The examples below use the bare command; prefix with uv run if you skipped the
install step. The import package is flipmail (the command is mailbox) — see
docs/Project_Structure.md for why.
mailbox --help
mailbox subscribers list # first 20 subscribers
mailbox subscribers list --status active --limit 50
mailbox subscribers list --all # walk every page
mailbox subscribers list --tags # include each subscriber's tagsmailbox tags list # the account's tags
mailbox tags create "Volunteers" # idempotent
# Add/remove a tag, by id or email, individually or in bulk.
# TAG is a tag name (resolved for you) or a numeric tag id.
mailbox tags add "Volunteers" 12345 ada@flip.museum
mailbox tags add "Volunteers" --from-status active --dry-run
mailbox tags add "Volunteers" --all --dry-run # everyone (preview)
mailbox tags add "Volunteers" --from-file emails.txt # '-' = stdin
mailbox tags add "New Tag" 12345 --create-missing # create then tag
mailbox tags remove "Volunteers" 12345Mutating commands are deliberately careful: pass --dry-run to preview, and they
ask for confirmation unless you pass --yes. Adding a tag can trigger Kit
automations and send email, so it can't be undone — preview first. Bulk runs
loop one API call per subscriber (API keys can't use Kit's bulk endpoints), so
large batches are rate-limited to ~120/min and take a while.
For remove, --all and --from-status only touch subscribers who actually have
the tag (looked up via the tag's subscriber list), so a bulk untag costs one call
per holder, not one per subscriber in the account. (add --all necessarily targets
everyone, since you're tagging people who don't have it yet.)
remove verifies each subscriber actually has the tag before deleting, so it reports
N removed, M weren't tagged, K failed — never a false "removed" on a no-op. (Kit's
tag listings are eventually consistent and can show subscribers who no longer hold a
tag; the per-subscriber check is the source of truth.)
Example output:
ID EMAIL NAME STATE
4163290803 ada@example.com Ada active
4163249277 grace@example.com Grace active
2 subscriber(s).
You can also drive the client library directly:
uv run python -c "from flipmail.kit import KitClient; print(KitClient().get_subscriber(1))"Developer documentation lives in docs/. Start with docs/KitAPI.md before writing any code that touches Kit.
Sending email is hard to undo. Operations that send mail or mutate subscribers must be deliberate, idempotent, and dry-run-able. See the safety section in docs/KitAPI.md.