A Python wrapper for the Emailnator service providing both synchronous and asynchronous APIs.
Project description
emailnator-wrapper
Asynchronous and synchronous API wrapper for EmailNator. Provides a small, well-typed SDK to generate temporary Gmail-style addresses and read incoming messages. Designed for both script usage and integration into larger automation/test suites.
Features
- Fully asynchronous core using
httpx.AsyncClient. - Optional synchronous wrapper for blocking workflows.
- Automatic XSRF token management (fetch, decode, refresh) via
XsrfManager. - Async-aware initialization helpers (metaclasses / factories) so classes can expose
__ainit__. - Async-safe singletons (
AsyncSingletonMeta) where appropriate (HTTP client). - Configurable via YAML (
config.yaml) with optional proxy support. - Clear, Google-style docstrings and type annotations.
Requirements
-
Python 3.11+ (works on 3.13).
-
Dependencies (typical):
httpxPyYAMLpytest/pytest-asynciofor tests
Installation
pip install email-wrapper
Configuration
emailnator/config/config.yaml (example):
BASE_URL: https://www.emailnator.com
TIMEOUT: 15
USE_HTTP2: true
USER_AGENT: "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0"
GMAIL_CONFIG:
- dotGmail
- plusGmail
PROXY: null
Notes
PROXY: nullsetsconfig.PROXYtoNone. Do not use the literal string"None"—httpxwill reject that as an invalid proxy URL.- Keep credentials / secrets out of the YAML in public repos.
Quickstart — Asynchronous (recommended)
Save the example below as examples/async_example.py.
# Copyright (C) 2025 unelected
#
# This file is part of account_generator.
#
# account_generator is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# account_generator is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with account_generator. If not, see
# <https://www.gnu.org/licenses/>.
"""
Example usage of the asynchronous AsyncEmailGenerator.
This script demonstrates:
1. Creating the asynchronous AsyncEmailGenerator (awaitable constructor).
2. Generating a single temporary email address.
3. Retrieving messages for that address.
4. Printing results.
"""
import asyncio
from emailnator.asyncio.email_generator import AsyncEmailGenerator
async def generate_email_and_get_messages() -> None:
"""
Initialize the async generator, produce an email and fetch messages.
"""
generator = await AsyncEmailGenerator()
email_list = await generator.generate_email()
email = email_list[0]
messages = await generator.get_messages(email)
print(f"Email: {email}\nMessages: {messages}")
if __name__ == "__main__":
asyncio.run(generate_email_and_get_messages())
Quickstart — Synchronous wrapper
Save as examples/sync_example.py.
# Copyright (C) 2025 unelected
#
# This file is part of account_generator.
#
# account_generator is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# account_generator is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with account_generator. If not, see
# <https://www.gnu.org/licenses/>.
"""
Synchronous example using EmailGenerator wrapper.
This demonstrates creating the blocking wrapper and using it to generate
an email and retrieve messages in a non-async program.
"""
from emailnator.sync.email_generator import EmailGenerator
def main() -> None:
gen = EmailGenerator()
email = gen.generate_email()
messages = gen.get_messages(email)
print(f"Email: {email}\nMessages: {messages}")
if __name__ == "__main__":
main()
Public API overview
-
emailnator.asyncio.email_generator.AsyncEmailGeneratorHigh-level async facade. Useawait AsyncEmailGenerator(). -
emailnator.asyncio.generators.GeneratorsEndpoint wrapper for/generate-email. Providesgenerate_email()andgenerate_bulk_emails(). -
emailnator.asyncio.message_getter.MessageGetterFetch and parse messages for a given temporary email address. -
emailnator.asyncio.builders.AsyncEmailnatorClientHTTP client singleton (usesAsyncSingletonMeta). Exposesget_client(),get_headers(),refresh_token(). -
emailnator.asyncio.builders.helpers.xsrf_token_service.XsrfManagerEncapsulates XSRF lifecycle:ensure_token(),refresh(),get_token(),get_headers(). -
emailnator.config.configLoadsconfig.yamltoconfigobject with attributesBASE_URL,TIMEOUT,USE_HTTP2,USER_AGENT,GMAIL_CONFIG,PROXY.
Behavior notes & gotchas
- Await the constructor if using metaclass-based
__ainit__:obj = await ClassName(). If you forgetawait, you get a coroutine object with no attributes. - Proxy value in YAML must be
nullfor no proxy. String"None"will breakhttpx. - Cloudflare / Bot protection: EmailNator may be behind challenges (403/419). Temporary addresses and token flows can be blocked by anti-bot measures — the library attempts to read
XSRF-TOKENcookie, but if the site requires JavaScript challenges, consider using a Playwright-based flow or proper proxies. - Event loop management: Avoid calling
asyncio.run()inside already-running event loops. For synchronous wrapper, use a dedicated factory that creates its own loop safely.
Error handling & common troubleshooting
coroutine object has no attribute '...'— forgotawaiton constructor.RuntimeWarning: coroutine was never awaited— coroutine was created and not awaited; search for returns of coroutines.ValueError: Unknown scheme for proxy URL "None"—config.PROXYis the string"None", fix YAML tonullor code to coerceNone.- HTTP 419 / Page Expired — XSRF token missing or expired; check
XsrfManagerand cookie extraction. - HTTP 403 Cloudflare — site-side bot protection.
Contributing
- Fork, branch
feature/..., implement, add tests, open PR. - Keep changes backwards-compatible for public API unless you bump major version.
- Follow project style: type annotations, Google-style docstrings, tests.
License
This project is licensed under GNU Affero General Public License v3 (AGPL-3.0).
Files to include in the repo
README.md(this file)pyproject.toml/setup.cfgwith dependencies and dev extrasemailnator/config/config.yamlexampleexamples/async_example.pyexamples/sync_example.pytests/with unit & async tests
Contact
Open an issue or submit a pull request for help, bug reports, or enhancements.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file emailnator_wrapper-1.1.1.tar.gz.
File metadata
- Download URL: emailnator_wrapper-1.1.1.tar.gz
- Upload date:
- Size: 30.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
99d44f54f6279b26351aa568f79305a208efbe239372a9af34fd87d1b398b62a
|
|
| MD5 |
aee4438f2985b9c0ce1b6f2e0723cf87
|
|
| BLAKE2b-256 |
b65fcc866ae53aa4afaf2de091edab9750789a189916f5568c11b6584d5faf83
|
File details
Details for the file emailnator_wrapper-1.1.1-py3-none-any.whl.
File metadata
- Download URL: emailnator_wrapper-1.1.1-py3-none-any.whl
- Upload date:
- Size: 43.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b8a7fe0293839e840316815aa656519c7ddcb7168c65fe42b8e8b985811b0c4b
|
|
| MD5 |
40526729a67c8e6d1d0d4d98e84b59d3
|
|
| BLAKE2b-256 |
c897946c1b7e2cab8b20817c39821dd28d55d96c51cf8b98b76d88468b815043
|