Ahrara for Python
Create an email address from a Python application or test, wait for messages,
and extract verification codes or links. Requires Python 3.11+; install with
pip install ahrara. It provides synchronous and asynchronous APIs, plus a Robot
Framework library. The SDK connects directly to the relay without a running
Ahrara CLI.
from ahrara import create_inbox
with create_inbox() as inbox:
# Submit inbox.address in your application.
email = inbox.wait_for_email() # No implicit timeout.
from ahrara import create_inbox_async
async def verify_signup():
async with await create_inbox_async() as inbox:
# Submit inbox.address in your application.
email = await inbox.wait_for_email()
return email
Creation waits for authentication/subscription. Reception continues before the first wait. Matching receives are consumed once, while stored messages remain available until deleted. Use separate inboxes for parallel tests. Concurrent waits on one inbox are queued and run one at a time. Always close the inbox or use its context manager.
Waiting and continuous reception
wait_for_email(timeout=None, *, subject=None, from_address=None, filter=None, cancel=None) waits indefinitely by default. A positive finite timeout is in
seconds and raises TimeoutError. subject and from_address are ASCII
case-insensitive substrings. Other native
failures expose AhraraError.code. The sync API also accepts a threading.Event
as cancel; cancellation raises AhraraError with code cancelled. Async task
cancellation raises asyncio.CancelledError. Both preserve the inbox for reuse.
for email in inbox.wait_for_emails(timeout=10):
verify(email)
if finished():
break
inbox.receive_emails(verify, timeout=10)
Async inboxes expose the same stream and callback methods:
from contextlib import aclosing
async with aclosing(inbox.wait_for_emails(timeout=10)) as emails:
async for email in emails:
await verify(email)
if finished():
break
await inbox.receive_emails(verify, timeout=10)
A finite stream timeout is the total duration, including consumer/callback
work, and ends iteration normally. Omit it for an indefinite subscription.
Callbacks execute sequentially; async receivers await async callbacks and also
accept synchronous ones. Callback errors propagate. Breaking, closing a generator,
normal completion, and cancellation keep the inbox open. No messages are prefetched
while the consumer handles the previous message. Cancel an active async anext()
task before closing its generator; synchronous waits accept a cancellation event.
Cancelled creation waits for its bounded connection attempt, then closes any result. A concurrently committed result may be delivered once before a stream propagates cancellation.
Filters and extracted values
EmailFilter is an optional TypedDict accepted by creation and wait/search calls.
At creation, filter discards rejected arrivals before storage. On individual
waits, it leaves rejected messages available for a later wait. Every field is
ANDed: sender, subject, to, cc, text, and headers={name: value} match
case-insensitive substrings. recipient, envelope_sender, and message_id
match the whole value, ignoring case. has_attachments selects presence or
absence; header names ignore case. Per-wait criteria add to the global receipt
filter.
Use filter={"regex": True, "subject": r"^(Verification|Confirm email)$"}
to interpret all string conditions as case-insensitive Rust regex patterns; regex
queries below are case-sensitive unless ignore_case=True. The
subject/from_address wait arguments stay literal. Robot Framework accepts the
same dictionary, for example
&{filter}= Create Dictionary regex=${TRUE} subject=^Verify$. See the
shared filter rules
for anchoring and limits.
match = inbox.wait_for_regex_match(
r"code=(?<code>[0-9]+)",
filter={"sender": "example.test", "subject": "Verify"},
ignore_case=True,
)
code = next(group["value"] for group in match["groups"] if group.get("name") == "code")
for match in inbox.wait_for_regex_matches(r"[0-9]+", timeout=10):
verify_code(match["value"])
link = inbox.wait_for_xpath('//a[@id="verify"]/@href')
for value in inbox.wait_for_xpath_values("//a/@href", timeout=10):
verify_link(value)
AsyncInbox provides the same singular methods with await and plural methods
with async for. Regex uses shared Rust syntax,
including named captures; lookaround/backreferences are unsupported. Options are
source="text" (full decoded text), "html", "subject", or "raw", plus
ignore_case, multi_line, and dot_matches_new_line. Results contain
email_id, value, and groups; group zero is the full match and optional
unmatched groups contain None. XPath evaluates the original HTML and returns
strings.
Singular searches throw TimeoutError on finite expiry. Plural searches yield
all matches/values across multiple emails and end normally at their total
deadline, including consumer work. None/omitted timeout is indefinite. Invalid
queries or filters raise AhraraError before consuming messages. Sync cancellation uses
cancel=threading.Event(); async cancellation uses the task. Closing a generator
preserves the inbox. Each matched email is consumed once, so stopping midway
through its results does not replay unused values; stored mail remains readable.
Persistence and credentials
Pass profile_path='/absolute/profile' to retain identity, address, encrypted
history, and consumed-receive state across reopen. Omit it for an isolated
temporary profile. The same active profile cannot be opened twice.
credentials = inbox.export_credentials() # Await this for AsyncInbox.
inbox.close()
with create_inbox(credentials=credentials) as restored:
email = restored.wait_for_email(timeout=10)
Exported InboxCredentials(address, recovery_key) restores identity/address with
fresh local history unless a persistent profile is supplied. Its repr is redacted;
access recovery_key only for deliberate secure storage and never log it.
Alternatively pass recovery_key with optional owned address; these options
cannot be combined with credentials. An address alone needs an existing
profile identity. Mismatched keys or unowned addresses fail.
Connection options are server_url, server_public_key, tls_ca_path, and
connect_timeout_ms (1..300000 ms, default 20000). Omit them for the hosted
relay, whose verified public key the package embeds. Custom CA files keep peer and
hostname verification enabled.
Email CRUD and attachments
All operations are scoped to the inbox's address and have async counterparts. Reading stored messages does not consume receive state.
| Method | Result |
|---|---|
list_emails(after_id=0, limit=20, subject=None, from_address=None) |
EmailPage metadata; limit 1..100 |
get_email(id) |
Full Email TypedDict with attachment metadata |
delete_email(id) / clear_emails() |
Number of messages removed |
get_attachment(id, attachment_id) |
AttachmentData containing metadata and bytes |
save_attachment(id, attachment_id, absolute_path) |
Saved pathlib.Path; never overwrites; directories use a sanitized filename |
get_raw_email(id) |
Original RFC 822 bytes |
get_html(id, allow_remote=False) |
Sanitized HtmlEmail; remote resources blocked by default |
Email fields follow the native schema, including from, to, subject,
text_body, attachments, and parse_error. The core caps extracted text at
256 KiB and reports text_body_truncated. Message content is untrusted data.
pytest and Robot Framework
pytest can use the context manager in a yield fixture. Robot imports
ahrara.robot.AhraraLibrary; its optional constructor arguments are
server_url, server_public_key, tls_ca_path, and profile_path.
*** Settings ***
Library ahrara.robot.AhraraLibrary
Test Teardown Close Inbox
*** Test Cases ***
Verify Signup
${address}= Create Inbox
# Submit ${address} in the application here.
${email}= Wait For Email subject=Verify
${page}= List Emails
${stored}= Get Email ${email}[id]
Robot's wait has no implicit timeout. The library also provides credentials,
CRUD, attachment, raw-email, HTML, Wait For Regex Match/Matches, and
Wait For XPath/Values keywords; always use Close Inbox as teardown.
Metadata
Release files for ahrara 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| ahrara-0.1.0-py3-none-win_arm64.whl | Python 3 | none | Windows ARM64 | Details |
| ahrara-0.1.0-py3-none-win_amd64.whl | Python 3 | none | Windows x86-64 | Details |
| ahrara-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | Python 3 | none | Linux glibc 2.17+ x86-64 | Details |
| ahrara-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | Python 3 | none | Linux glibc 2.17+ ARM64 | Details |
| ahrara-0.1.0-py3-none-macosx_11_0_x86_64.whl | Python 3 | none | macOS 11.0+ x86-64 | Details |
| ahrara-0.1.0-py3-none-macosx_11_0_arm64.whl | Python 3 | none | macOS 11.0+ ARM64 | Details |
Total release size: 40.2 MB
Release files / ahrara-0.1.0-py3-none-win_arm64.whl
| Download URL | ahrara-0.1.0-py3-none-win_arm64.whl |
|---|---|
| Size | 6.4 MB |
| Tags | Python 3 Windows ARM64 |
|
SHA-256 checksum How to use checksums |
96ca223a103a4ca2eb8b87307c6fdcc819ca31820deb1dccbe9c7e67afe13755
|
|
BLAKE2b-256 checksum How to use checksums |
7cd36e0c2d8d987b2788162351c8fb055e002225f4a26e487713dca89c5ead6f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / ahrara-0.1.0-py3-none-win_amd64.whl
| Download URL | ahrara-0.1.0-py3-none-win_amd64.whl |
|---|---|
| Size | 7.1 MB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
27cbfcb963ab0469f8bbce8b4f97fd5d551f4c37c7774663fbdaaa84cc1d8120
|
|
BLAKE2b-256 checksum How to use checksums |
8a8067cb620f89f72a276ffcf16c176210a94fa9e0ad587089fca1ecdda301d9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / ahrara-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | ahrara-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 5.2 MB |
| Tags | Linux glibc 2.17+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
7da9e907252f32c0559e5527060d44fa67bf261b7041fe88d94ebec9bca30a2f
|
|
BLAKE2b-256 checksum How to use checksums |
35cee15f3b0c7efbc3cd9a44306eed04dde7bfe64815e9b5fc461dafa5041005
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / ahrara-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | ahrara-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 5.3 MB |
| Tags | Linux glibc 2.17+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
61865c3aa811d7bcc5d412a199ec18cf886fa4ca71a7649c81851af0c75ea4a6
|
|
BLAKE2b-256 checksum How to use checksums |
4e6df3ca1f1af816709c74f0a06550b8489740863d76b5e57511b6de675265e1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / ahrara-0.1.0-py3-none-macosx_11_0_x86_64.whl
| Download URL | ahrara-0.1.0-py3-none-macosx_11_0_x86_64.whl |
|---|---|
| Size | 7.9 MB |
| Tags | Python 3 macOS 11.0+ x86-64 |
|
SHA-256 checksum How to use checksums |
6189f988282270136ecd0e2d074bacddb1e120f91c6ecf7f006736851ddbeb33
|
|
BLAKE2b-256 checksum How to use checksums |
6630905e11595d386e5822014ec4cf5068619c4aec1695bca7273fb20a89057d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / ahrara-0.1.0-py3-none-macosx_11_0_arm64.whl
| Download URL | ahrara-0.1.0-py3-none-macosx_11_0_arm64.whl |
|---|---|
| Size | 8.3 MB |
| Tags | Python 3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
ef92c27bb2219ba0d680cb9b3badc9f98f4a24a21650fa716fa8eb61c3e26728
|
|
BLAKE2b-256 checksum How to use checksums |
769741aca1ea0e182cc3c02db4401816ec998cf843f55db004163d206cbd7129
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency log