All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Updated dev tooling: mypy 2.x, ruff 0.15.x, Poetry 2.4.1, and pre-commit hooks
postmark.sync: Gunicorn and Odoo devs, rejoice! ...the module-level event loop thread is now fork-safe. Previously, importingpostmark.syncbefore a process fork caused child processes to inherit a stale event loop with no running thread, causing all sync API calls to hang indefinitely. The loop and thread are now created lazily on first use and recreated automatically when a PID change is detected. (Good eye, @yibudak.)
SyncServerClientandSyncAccountClient— synchronous wrappers around the async clients, backed by a single daemon thread with a persistent asyncio event loop. Enables SDK use in scripts, Flask apps, and Jupyter notebooks withoutasync/await. HTTP connection pooling is retained across calls for performance.- Examples reorganized into
examples/async/andexamples/sync/directories with parallel coverage, plus two new sync-only examples (send_sync_simple.py,send_sync_batch.py). - 31 new tests for sync client behavior (
tests/test_sync_client.py).
- Upgraded
httpxdependency to0.28.1. - CI: expanded test matrix to include Python 3.13 and 3.14.
- CI: updated GitHub Actions to
actions/checkout@v6,actions/setup-python@v6,actions/cache@v5, and Poetry2.3.4.
- README: logo image now uses an absolute raw GitHub URL so it renders correctly on the PyPI project page.
__version__resolves from thepostmark-pythondistribution metadata soX-Postmark-Client-Versionmatches afterpip install postmark-python(falls back to0.0.0when not installed as a package).
poetry.lockis tracked in version control again (removed from.gitignore) for reproducible installs and CI cache keys.- README: removed the misleading note about a future PyPI distribution under the name
postmark.
- Timeout error message now uses the client’s configured timeout with clearer numeric formatting (
:g), for bothServerClientandAccountClient. - Postmark API
ErrorCodevalues from JSON are coerced tointwhen sent as numeric strings; invalid values and booleans map toNoneso exception mapping stays reliable. - README quick start no longer imports
python-dotenv(a dev-only dependency); optional.envloading is described in a comment instead.
- PyPI distribution renamed from
postmarktopostmark-pythonto avoid clashing with the unrelatedpostmarkpackage on PyPI. The import name remainspostmark. - Trove classifier updated from Alpha to Beta (
Development Status :: 4 - Beta).
- Project URLs for PyPI metadata: repository, homepage (official libraries), documentation (wiki), and Issues link.
- Client identification on every request:
User-AgentasPython/{major}.{minor}.{micro},X-Postmark-Clientaspostmark-python,X-Postmark-Client-Versionas the installed SDK version, and a freshX-Postmark-Correlation-Id(UUID) per HTTP request. X-Request-Idfrom Postmark responses is now stored asrequest_idon allPostmarkAPIExceptionsubclasses and included in the exception__str__output when present — enabling direct support escalations.request_idincluded in structured log records for both successful requests and API errors.- Structured
extra={}fields on all log calls (method,endpoint,status_code,duration_ms,error_code,postmark_message,request_id) for compatibility with Datadog, Splunk, and other log aggregators. duration_mstiming on every request log record (success, error, and timeout).
- Upgraded
pytest-asyncioto^1.0.0and setasyncio_mode = "auto"to eliminate deprecation warnings on Python 3.12+.
- Initial release of the SDK.
ServerClientandAccountClientwith authentication, configurable retries, timeout, and optionalbase_urloverride for local mock servers.- Managers for outbound/inbound messages, bounces, templates, streams, suppressions, webhooks, stats, domains, sender signatures, and data removals.
- Async pagination via
paginate()utility;stream()methods onOutboundManagerandBounceManager. - Typed request/response models backed by Pydantic v2.
- Pytest test suite.