- Explicit
__all__declaration inmailgun.clientto cleanly isolate the public API namespace. - A
__repr__method to theClientandBaseEndpointclasses to improve developer experience (DX) during console debugging (showing target routes instead of memory addresses). - Security guardrail (CWE-319) in
Configthat logs a warning if a cleartexthttp://API URL is configured. - Python 3.14 support to the GitHub Actions test matrix.
- Implemented Smart Logging (telemetry) in
ClientandAsyncClientto help users debug API requests, generated URLs, and server errors (404,400,429). - Smart Webhook Routing: Implemented payload-based routing for domain webhooks. The SDK dynamically routes to
v1,v3, orv4endpoints based on the HTTP method and presence of parameters likeevent_typesorurl. - Deprecation Interceptor: Added a registry and interception hook that emits non-breaking
DeprecationWarnings and logs when utilizing obsolete Mailgun APIs (e.g., v3 validations, legacy tags, v1 bounce-classification). - Added
build_path_from_keysutility inmailgun.handlers.utilsto centralize and dry up URL path generation across handlers. - Overrode dir in Client and AsyncClient to expose dynamic endpoint routes (e.g., .messages, .domains) directly to IDE autocompletion engines (VS Code, PyCharm).
- Native dynamic routing support for Mailgun Optimize, Validations Service, and Email Preview APIs without requiring new custom handlers.
- Explicit support for raw MIME string (
multipart/form-data) uploads via thefilesparameter in the.create()method (essential forclient.mimemessage). - Advanced path interpolation in
handle_defaultto automatically inject inline URL parameters (e.g.,/v2/x509/{domain}/status). - Added
MailgunTimeoutError(inheriting fromApiErrorandTimeoutError) to cleanly distinguish API connection timeouts from standard system timeouts. - Implemented
ROUTE_ALIASESin the configuration engine to safely route virtual SDK properties (e.g.,domains_webhooks) without hardcoding intercept logic. - Added
TimeoutTypetype alias for cleaner and more robust type hinting across the HTTP client. - Added a new "Logging & Debugging" section to
README.md. - An intelligent live meta-testing suite (
test_routing_meta_live.py) to strictly verify SDK endpoint aliases against live Mailgun servers. - PEP 561 Compliance: Added a
py.typedmarker to expose the SDK's strict type hints to downstream users (mypy,pyright). - DX Tooling: Added a unified
manage.shscript to streamline local formatting, linting, testing, and benchmarking. - Routing Engine Meta-Tests: Added
test_routing_engine.pyto dynamically validate URL generation for all 58+ supported endpoints.
- Memory Optimization: Enforced
__slots__onClientandEndpointclasses to eliminate dynamic__dict__overhead, reducing Garbage Collection pauses and improving overall throughput by ~8-10%. - Exception Chaining (PEP 3134): Network connection errors from
httpxandrequestsare now explicitly chained (raise from), preventing the swallowing of root-cause infrastructure tracebacks. - Refactored the
Configrouting engine to use a deterministic, data-driven approach (EXACT_ROUTESandPREFIX_ROUTES) for better maintainability. - Improved dynamic API version resolution for domain endpoints to gracefully switch between
v1,v3, andv4for nested resources, with a safe fallback tov3. - Secured internal configuration registries by wrapping them in
MappingProxyTypeto prevent accidental mutations of the client state. - Broadened type hints for
files(Any | None) andtimeout(int | float | tuple) to fully supportrequests/httpxcapabilities (like multipart lists) without triggering false positives in strict IDEs. - Performance: Implemented automated Payload Minification. The SDK now strips structural spaces from JSON payloads (
separators=(',', ':')), reducing network overhead by ~15-20% for large batch requests. - Performance: Memoized internal route resolution logic using
@lru_cachein_get_cached_route_data, eliminating redundant string splitting and dictionary lookups during repeated API calls. - Updated
DOMAIN_ENDPOINTSmapping to reflect Mailgun's latest architecture, officially movingtracking,click,open,unsubscribe, andwebhooksfromv1tov3. - Modernized the codebase using modern Python idioms (e.g.,
contextlib.suppress) and resolved strict typing errors forpyright. - Abstracted HTTP header manipulation into a centralized
_merge_headersmethod inBaseEndpoint, eliminating DRY violations across all sync and async HTTP verbs. - Hardened all URL handlers (
domains,ips,keys,mailinglists,metrics,routes,suppressions,tags) to use.rstrip("/")and safe.get("keys", [])dictionary lookups, preventing404 Not FoundandKeyErrorcrashes from malformed internal configurations. - Replaced
passblocks with explicitlogging.warningin integration tests to surface ignored 404s gracefully. - Documentation: Migrated all internal and public docstrings from legacy Sphinx/reST format to modern Google Style for cleaner readability and better IDE hover-hints.
- Updated Dependabot configuration to group minor and patch updates and limit open PRs.
- CI/CD Optimization: Grouped Dependabot updates (
minor-and-patch) to reduce Pull Request noise and optimized.editorconfig. - Migrated the fragmented linting and formatting pipeline (Flake8, Black, Pylint, Pyupgrade, etc.) to a unified, high-performance
ruffsetup in.pre-commit-config.yaml. - Refactored
api_callexception blocks to use theelseclause for successful returns, adhering to strict Ruff (TRY300) standards. - Enabled pip dependency caching in GitHub Actions to drastically speed up CI workflows.
- Fixed API versioning collisions in
DOMAIN_ENDPOINTS(e.g., ensuringtrackingcorrectly resolves tov3instead ofv1). - Corrected the
credentialsroute prefix to properly inject thedomains/path segment. - Updated
README.mdwith new documentation, IDE DX features, and code examples for Validations & Optimize APIs. - Cleaned up obsolete unit tests that conflicted with the new forgiving dynamic Catch-All routing architecture.
- Fixed a silent data loss bug in
create()where customheaderspassed by the user were ignored instead of being merged into the request. - Fixed a kwargs collision bug in
update()by using.pop("headers")instead of.get()to prevent passing duplicate keyword arguments to the underlying request. - Preserved original tracebacks (PEP 3134) by properly chaining
TimeoutErrorandApiErrorusingfrom e. - Used safely truncating massive HTML error responses to 500 characters (preventing a log-flooding vulnerability (OWASP CWE-532)).
- Replaced a fragile
try/except TypeErrorstatus code check with robustgetattrandisinstancevalidation to prevent masking unrelated exceptions. - Resolved
httpxDeprecationWarninginAsyncEndpointby properly routing serialized JSON string payloads to thecontentparameter instead ofdata. - Fixed a bug in
domains_handlerwhere intermediate path segments were sometimes dropped for nested resources like/credentialsor/ips. - Fixed flaky integration tests failing with
429 Too Many Requestsand403 Limits Exceededby adding proper eventual consistency delays and state teardowns. - Fixed DKIM key generation tests to use the
-traditionalOpenSSL flag, ensuring valid PKCS1 format compatibility. - Fixed DKIM selector test names to strictly comply with RFC 6376 formatting (replaced underscores with hyphens).
- Python Data Model Integrity: The Catch-All router (
__getattr__) now strictly rejects Python magic methods (__dunder__), preventing crashes when usinghasattr(),pickle, orcopy.deepcopy(). - Version Drift: Corrected endpoints for
spamtrapsandip_whitelistto route to their modernv2Mailgun backends. - Fixed a
TypeError: got multiple values for keyword argument 'headers'crash when passing custom headers to.get(),.put(),.patch(), and.delete()methods by safely popping headers fromkwargsbefore argument unpacking. - Fixed a routing bug where the greedy
domainsrouter swallowed thedomains_webhooksidentifier, causing webhook payload updates to drop thewebhook_nameand hit the wrong API endpoint. - Fixed a bug where
AsyncClienttransports were permanently closed after exiting anasync withcontext manager, allowing safe client reuse across multiple blocks. - Fixed
AttributeErrortraceback leakage by strictly suppressing internalKeyErrors from the dynamic router (raise ... from None). - Fixed a silent string-concatenation bug that could generate invalid double-slashes (
//) in base URLs during theConfigengine initialization. - Fixed
email_validation_examples.pyto correctlyraisetheValueErroron empty files instead of failing silently.
- OWASP Credential Protection: Implemented a
SecretAuthtuple subclass to securely redact the Mailgun API key from accidental exposure in memory dumps, tracebacks, andrepr()logs. - OWASP Input Validation: Added strict sanitization in
Client._validate_authto strip trailing whitespace and block HTTP Header Injection attacks (rejecting\nand\rcharacters in API keys). - CWE-113 (HTTP Header Injection): Implemented strict CRLF (
\r\n) sanitization insideSecurityGuard.sanitize_headersto block malicious header manipulation. - Supply Chain Security: Patched a potential OS Command Injection vulnerability in GitHub Actions (
publish.yml) by safely routinggithub.*contexts through environment variables. - CWE-22 (Path Traversal): Enforced strict URL-encoding via
sanitize_path_segmentonwebhook_nameparameters to neutralize path traversal injection attempts in thehandle_webhooksrouter.
- PR_39 - Release 1.7.0
- PR_38 - build(deps): Bump conda-incubator/setup-miniconda from 3.3.0 to 4.0.1
- PR_36 - Improve client, update & fix tests
- PR_35 - Removed _prepare_files logic
- PR_34 - Improve the Config class and routes
- PR_33 - Refactored test framework
- PR_31 - Add missing py.typed in module directory
- PR_30 - build(deps): Bump conda-incubator/setup-miniconda from 3.2.0 to 3.3.0
1.6.0 - 2026-01-08
-
Add Keys and Domain Keys API endpoints:
- Add
handle_keystomailgun.handlers.keys_handler. - Add
handle_dkimkeystomailgun.handlers.domains_handler. - Add "dkim" key to special cases in the class
Config.
- Add
-
Examples:
- Add the
get_dkim_keys(),post_dkim_keys(),delete_dkim_keys()examples tomailgun/examples/domain_examples.py. - Add the
get_keys(),post_keys(),delete_key(),regenerate_key()examples tomailgun/examples/keys_examples.py.
- Add the
-
Docs:
- Add
KeysandDomain Keyssections with examples toREADME.md. - Add docstrings to the test class
KeysTests&AsyncKeysTestsand their methods. - Add
CONTRIBUTING.md. - Add
MANIFEST.in.
- Add
-
Tests:
- Add dkim keys tests to
DomainTestsand onlytest_get_dkim_keys,test_post_dkim_keys_invalid_pem_stringtoAsyncDomainTests. - Add classes
KeysTestsandAsyncKeysTeststotests/tests.py. - Add keys tests to
KeysTestsandAsyncKeysTests.
- Add dkim keys tests to
-
CI:
- Add more pre-commit hooks.
- Update
get_own_user_details()by creatingclient_with_secret_keyinmailgun/examples/users_examples.py. - Improve the users' example in
README.md. - Fix markdown structure in
README.md. - Update environment variables in
README.md. - Move
BounceClassificationTeststo another place intests/tests.py. - Replace some pytest's skip marks with xfail.
- Disable
codespellpre-commit hook as it lashes withtypos. - Update
pre-commithooks to the latest versions. - Update test dependencies: add
opensslandpytest-asynciotoenvironment-dev.yamlandpyproject.toml. - Add
.server.keyto.gitignore. - Add a constraint
py<311fortyping_extensions >=4.7.1in filesenvironment.yaml,environment-dev.yaml,pyproject.toml, and inmailgun/client.py. - Improve
pyproject.toml.
1.5.0 - 2025-12-11
-
Add
AsyncClientandAsyncEndpointthat work based on asynchronous approach. Signatures and usage is basically the same butAsyncClientsupports async context manager mode. -
Add
httpx >=0.24.0as an additional runtime dependency in order to support async/await and alsotyping_extensions >=4.7.1toenvironment.yaml,environment-dev.yaml, andpyproject.toml. -
Add missing endpoints:
- Add
"users","me"to theuserskey of special cases in the classConfig. - Add
handle_userstomailgun.handlers.users_handlerfor parsing Users API. - Add
handle_mailboxes_credentials()tomailgun.handlers.domains_handlerfor parsingUpdate Mailgun SMTP credentialsin Credentials API.
- Add
-
Examples:
- Add async examples to
async_client_examples.py. - Move credentials examples from
mailgun/examples/domain_examples.pytomailgun/examples/credentials_examples.pyand add a new exampleput_mailboxes_credentials(). - Add the
get_routes_match()example tomailgun/examples/routes_examples.py. - Add the
update_template_version_copy()example tomailgun/examples/templates_examples.py. - Add
mailgun/examples/users_examples.py.
- Add async examples to
-
Docs:
- Add the
AsyncClientsection toREADME.md. - Add
CredentialsandUserssections with examples toREADME.md. - Add docstrings to the test class
UsersTests&AsyncUsersTestsand theirs methods.
- Add the
-
Tests:
- Add same tests for
AsyncClientas exist forClient. - Add
test_put_mailboxes_credentialstoDomainTestsandAsyncDomainTests. - Add
test_get_routes_matchtoRoutesTestsandAsyncRoutesTests. - Add
test_update_template_version_copytoTemplatesTestsandAsyncTemplatesTests. - Add classes
UsersTestsandAsyncUsersTeststotests/tests.py.
- Add same tests for
- Update
handle_templates()inmailgun/handlers/templates_handler.pyto handlenew_tag. - Update CI workflows: update
pre-commithooks to the latest versions. - Modify
mypy's additional_dependencies in.pre-commit-config.yamlto suppresserror: Untyped decorator makes functionby addingpytest-order. - Replace spaces with tabs in
Makefile. - Update
Makefile: addmake check-envand improvemake test.
1.4.0 - 2025-11-20
- Add the
Bounce Classificationendpoint:- Add
bounce-classification,metricsto thebounceclassificationkey of special cases in the classConfig. - Add
bounce_classification_handler.pyto parse Bounce Classification API. - Add
mailgun/examples/bounce_classification_examples.pywithpost_list_statistic_v2(). - Add
Bounce Classificationsections with an example toREADME.md. - Add class
BounceClassificationTeststotests/tests.py. - Add docstrings to the test class
BounceClassificationTestsand its methods.
- Add
- Fix
Metrics,Tags New&Logsdocstrings in tests. - Update CI workflows: update
pre-commithooks to the latest versions. - Apply linters: remove redundant
type: ignore.
1.3.0 - 2025-11-08
- Add the
Tags Newendpoint:- Add
tagsto theanalyticskey of special cases in the classEndpoint. - Add
mailgun/examples/tags_new_examples.pywithpost_analytics_tags(),update_analytics_tags(),delete_analytics_tags(),get_account_analytics_tag_limit_information(). - Add
Tags Newsections with examples toREADME.md. - Add class
TagsNewTeststo tests/tests.py.
- Add
- Add
# pragma: allowlist secretfor pseudo-passwords. - Add the
pytest-orderpackage topyproject.toml's test dependencies and toenvironment-dev.yamlfor ordering someDomainTests,MessagesandTagsNewTests. - Add docstrings to the test classes.
- Add Python 3.14 support.
- Update
metrics_handler.pyto parse Tags New API. - Mark deprecated
Tags APIinREADME.mdwith a warning. - Fix
Metrics&Logsdocstrings. - Format
README.md. - Use ordering for some tests by adding
@pytest.mark.order(N)to run specific tests sequentionally. It allows to remove some unnecessary@pytest.mark.skip() - Rename some test classes, e.i.,
ComplaintsTest->ComplaintsTestsfor consistency. - Use
datetimeforLogsTestsdata instead of static date strings. - Update CI workflows: update
pre-commithooks to the latest versions; add py314 support (limited). - Set
line-lengthto100across the linters inpyproject.toml.
1.2.0 - 2025-10-02
- Add the Logs endpoint:
- Add
logsto theanalyticskey of special cases - Add
mailgun/examples/logs_examples.pywithpost_analytics_logs() - Add class
LogsTestto tests/tests.py - Add
Get account logssections with an example toREADME.md - Add class
LogsTestto tests/tests.py
- Add
- Add
blacktodarker's additional_dependencies in.pre-commit-config.yaml - Add docstrings to the test classes.
- Update pre-commit hooks to the latest versions
- Fix indentation of the
post_bounces()example inREADME.md - Fix some pylint warnings related to docstrings
- Update CI workflows
1.1.0 - 2025-07-12
- Add the Metrics endpoint:
- Add the
analyticskey toConfig's__getitem__and special cases - Add
mailgun/handlers/metrics_handler.pywithhandle_metrics() - Add
mailgun/examples/metrics_examples.pywithpost_analytics_metrics()andpost_analytics_usage_metrics() - Add class
MetricsTestto tests/tests.py - Add
Get account metricsandGet account usage metricssections with examples toREADME.md
- Add the
- Add
pydocstylepre-commit hook - Add
types-requeststomypy's additional_dependencies
- Breaking changes: drop support for Python 3.9
- Improve a conda recipe
- Enable
refurbinenvironment-dev.yaml - Use
project.licenseandproject.license-filesinpyproject.tomlbecause of relying onsetuptools >=77. - Update pre-commit hooks to the latest versions
- Fix type hints in
mailgun/handlers/domains_handler.pyandmailgun/handlers/ip_pools_handler.py - Update dependency pinning in
README.md
- Remove
_version.pyfrom tracking and add to.gitignore - Remove the
wheelbuild dependency
1.0.2 - 2025-06-24
- docs: Minor clean up in README.md
- ci: Update pre-commit hooks to the latest versions
- docs: Add the Security Policy file SECURITY.md
- ci: Use permissions: contents: read in all CI workflow files explicitly
- ci: Use commit hashes to ensure reproducible builds
- build: Update dependency pinning: requests>=2.32.4
- PR_13 - Release v1.0.2: Improve CI workflows & packaging
1.0.1 - 2025-05-27
- docs: Fixed package name in README.md
- PR_11 - Fix package name
1.0.0 - 2025-04-22
- Initial release