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.
- Type checking with ty as the authoritative checker: a
ty.tomlconfig, atydev dependency, andtests/test_type_check.py, which fails the suite on any diagnostic (and skips when ty isn't installed). The tree is at zero diagnostics, checked against Python 3.10 — the floor of the supported range — so nothing newer than 3.10 slips into the public API
- Fixed the type errors and removed the 13 stale
# type: ignorecomments thatty checkreported. Two were real latent crashes inexample_client/client.py, which used a subscriber and its UUID without checking either forNone; the example now guards once, up front, instead of suppressing the warnings
- Campaign sending support, covering the two endpoints that actually deliver mail:
test_campaign(campaign_id, emails)sends a one-off test copy to specific subscriber addresses (POST /api/campaigns/{id}/test) without touching the campaign or its stats, andset_campaign_status(campaign_id, status)moves a campaign through its lifecycle (PUT /api/campaigns/{id}/status) — this is how a draft is started, sinceupdate_campaign()cannot change status start_campaign(),pause_campaign(), andcancel_campaign()convenience wrappers overset_campaign_status(), in the spirit ofenable_subscriber()/disable_subscriber()/block_subscriber()models.CampaignStatusesenum (draft,scheduled,running,paused,cancelled,finished), so an invalid status is caught client-side instead of surfacing as a Postgres enum error in an HTTP 500
0.4.3 - 2026-06-11
- Enrich the PyPI package metadata with a broader set of keywords (listmonk, email-marketing, campaigns, subscribers, transactional-email, etc.) for better discoverability
- Exclude the
testsdirectory from the published wheel and sdist, shrinking the installed package
0.4.2 - 2026-06-09
- Add media upload and campaign attachment support: new
upload_media()function andMediamodel, plus amedia_idsparameter oncreate_campaign()andupdate_campaign(). Updates preserve a campaign's existing attachments unlessmedia_idsis passed explicitly. (fixes #16) - Documentation site at https://mkennedy.codes/docs/listmonk/ generated from the docstrings with Great Docs
- Ship a
py.typedmarker (and theTyping :: Typedclassifier) so mypy/pyright type-check against the library's annotations create_list(),update_list(), anddelete_list()now accept the optionaltimeout_configparameter like every other network call (delete_list()previously hardcoded a 30-second timeout; all three now default to 10 seconds)
- Import
httpx2directly instead of aliasing it ashttpx, so signatures, docstrings, and the docs site all showhttpx2.Timeout/httpx2.HTTPStatusError— the names users actually import - Tighten public signatures to match documented behavior: required parameters are no longer
Optional(create_campaign(name, subject),create_template(name, body),delete_campaign(campaign_id),delete_template(template_id),set_default_template(template_id),confirm_optin(...)), and functions that can never returnNoneno longer claimOptionalreturns (list_by_id,campaign_preview_by_id,template_preview_by_id,create_campaign,create_template,create_list,update_list) - Fix the
headersparameter annotation oncreate_campaign()— it is a list of single-entry dicts, not a dict - Accuracy pass over docstrings, the README, and the example client (corrected TLS/certifi guidance, README samples that would not run as written, stale claims about unimplemented list/template APIs)
- Fix
update_list()sending the list type aslist_typeinstead oftype, so changing a list's type now actually takes effect - Fix
Subscriber.model_dump()crashing on server-populated subscribers (list-membership dicts and aNoneupdated_atnow serialize cleanly) - Fix the
list_by_id()workaround for listmonk#2117 crashing withAttributeErrorwhen the server returns a result set (dict access instead of attribute access) - Fix repeat
login()calls returningTruewithout re-validating the new credentials against the server
0.4.1 - 2026-06-03
- Migrate the HTTP backend from
httpxtohttpx2, the Pydantic-maintained fork, after the originalhttpxproject paused releases and locked down its issue tracker.httpx2is imported internally ashttpx, so the public API and all call sites are unchanged. - TLS certificates continue to be validated against the bundled
certifiCA list (thehttpx2default). If you self-host Listmonk behind a custom or corporate CA, setSSL_CERT_FILE/SSL_CERT_DIRto point at your CA bundle. See the SSL entry in the README F.A.Q. - If you pass a custom
timeout_config, construct it withhttpx2.Timeout(...)(now the bundled dependency) instead ofhttpx.Timeout(...).
0.4.0 - 2026-04-08
- Add
altbodysupport tosend_transactional_email()for multipart HTML transactional emails
0.3.13 - 2026-04-03
- Fix
confirm_optin()returningFalseon non-English Listmonk instances by using HTTP status codes instead of hardcoded English response strings (fixes #23)
0.3.12 - 2026-04-03
- Make subscriber
namefield optional inSubscriber,CreateSubscriberModel, andcreate_subscriber()to match the Listmonk API/UI behavior (fixes #15)
0.3.11 - 2026-04-03
- Fix campaign creation failing with listmonk server 6.0.0 -
headersfield now correctly uses a list of dictionaries instead of a plain dictionary (PR #28)
0.3.10 - 2026-01-28
- Add update_list function (thanks @ChrisH861, PR #27)
0.3.9 - 2026-01-05
- Add add_subscribers_to_lists function (thanks @MochaSteve256)
- Loosen some of the types to allow more flexible usage (avoid type errors when DTOs/ViewModels/etc have VALUE|None typing but are known to be in a good state)
- Refactor client implementation to improve organization and maintainability
0.3.8 - 2025-10-22
- Support for subject parameter in transactional templates (PR #24)
- FAQ section to README.md (PR #22)
- Four new API methods to the public interface
- CLAUDE.md with project overview, development commands, code style, and key patterns
- WARP.md documentation
- Ruff formatting configuration
- Extensive type annotation improvements for better IDE support (PyLance/VS Code)
- HTTP response validation and parsing refactored for better error handling
- Headers type fix: now properly uses string values instead of list of dictionaries
- Code formatting with ruff throughout the codebase
- Documentation improvements in README.md
- Custom exception renamed from
FileNotFoundErrortoListmonkFileNotFoundErrorto avoid builtin conflict - Non-string to string types in
__all__exports - Type inference error in code fragments