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 standalone scripts and integration into automation or testing pipelines.
✅ Fully asynchronous core using httpx.AsyncClient
✅ Synchronous wrapper for blocking workflows
✅ Automatic XSRF token management via XsrfManager
✅ Async-safe singleton HTTP client (AsyncSingletonMeta)
✅ YAML-based configurable setup with optional proxy
✅ Google-style docstrings and complete type hints
✅ Thoroughly tested with pytest (tests/sync, tests/asyncio)
📚 Documentation: ReadTheDocs
-
Python 3.9+ (tested on 3.13)
-
Dependencies:
httpxPyYAML- (for tests)
pytest,pytest-asyncio
pip install emailnator-wrapperemailnator/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)"
GMAIL_CONFIG:
- dotGmail
- plusGmail
PROXY: nullNotes:
- Use
null(not"None") to disable proxies. - Never store credentials or secrets in YAML files.
examples/async_example.py
import asyncio
from emailnator.asyncio.email_generator import AsyncEmailGenerator
async def main():
generator = await AsyncEmailGenerator()
email = await generator.generate_email()
messages = await generator.get_messages(email)
print(f"Email: {email}\nMessages: {messages}")
if __name__ == "__main__":
asyncio.run(main())examples/sync_example.py
from emailnator.sync.email_generator import EmailGenerator
def main():
gen = EmailGenerator()
email = gen.generate_email()
messages = gen.get_messages(email)
print(f"Email: {email}\nMessages: {messages}")
if __name__ == "__main__":
main()| Component | Description |
|---|---|
AsyncEmailGenerator |
High-level async interface. Awaitable constructor. |
Generators |
Wraps /generate-email endpoint (bulk + single). |
MessageGetter |
Retrieves and parses inbox messages. |
AsyncEmailnatorClient |
Shared async HTTP client singleton. |
XsrfManager |
Manages XSRF lifecycle and headers. |
config |
Loads YAML into structured config attributes. |
- Always
awaitthe constructor if using async metaclass (await AsyncEmailGenerator()). - YAML
PROXY: nullmeans no proxy — don’t use"None". - Possible HTTP issues (
403,419) may stem from bot protection — consider rotating proxies. - Avoid using
asyncio.run()inside an already running loop.
Tests are divided into two categories:
tests/
├── asyncio/
│ ├── test_generators.py
│ ├── test_message_getter.py
│ └── test_email_generator.py
└── sync/
├── test_generators_sync.py
└── test_email_generator_sync.py
pytest -vpytest tests/asyncio -vpytest tests/sync -vAll tests use pytest-asyncio and can be executed locally or in CI (GitHub Actions workflow provided).
Full API documentation is available on ReadTheDocs: -> https://emailnator-wrapper.readthedocs.io/en/latest/
You’ll find:
- Installation guide
- API references (async & sync layers)
- Architecture overview
- Examples & testing guide
| Issue | Cause / Fix |
|---|---|
coroutine object has no attribute |
Forgot to await async constructor. |
RuntimeWarning: coroutine was never awaited |
Created coroutine but didn’t await it. |
ValueError: Unknown scheme for proxy URL "None" |
Fix YAML: use null instead of "None". |
| HTTP 419 / “Page Expired” | Missing or expired XSRF token — refresh it. |
| HTTP 403 | Cloudflare or bot protection triggered — use proxy. |
- Fork the repository.
- Create a feature branch (
feature/my-change). - Add or update tests under
tests/. - Open a Pull Request.
✅ Follow code style: type hints, async-safe patterns, Google-style docstrings. ✅ Keep public API backward-compatible when possible.
Licensed under the GNU Affero General Public License v3 (AGPL-3.0). See LICENSE for full details.
| Resource | URL |
|---|---|
| 📘 Documentation | emailnator-wrapper.readthedocs.io |
| 🐍 PyPI | pypi.org/project/emailnator-wrapper |