Official Python SDK for Ujex Postbox — email-for-AI-agents with built-in prompt-injection scoring, auth verdicts, and plus-addressed task threading.
Project description
ujex-postbox
The Python SDK for Ujex Postbox — email for AI agents.
pip install ujex-postbox
30-second demo
from ujex_postbox import PostboxClient, plus_address
client = PostboxClient(device_key="ap_live_...", agent_id="agent-hello")
# Send
resp = client.send(
to=["alice@vendor.com"],
subject="Re: invoice",
body="On it — sending by Friday.",
require_human=True,
)
print(resp.id, resp.status, resp.quota_remaining)
# Plus-address a per-task inbox (no new inbox needed)
addr = plus_address("agent-hello@in.ujex.dev", task_id="proj-42-abc")
# -> agent-hello+proj-42-abc@in.ujex.dev
# Read an inbound message
m = client.read_message(agent_id="agent-hello", message_id="msg_01...")
print(m.pi_score, m.pi_reasons, m.auth_verdict.dkim, m.plus_task_id)
Why not AgentMail / SES / SendGrid?
Postbox surfaces Ujex's agent-specific signals as first-class fields:
| Field | What it gives you |
|---|---|
m.pi_score / m.pi_reasons |
Gemini-scored prompt-injection risk on every inbound, 0-1. |
m.auth_verdict.dkim/spf/dmarc |
RFC 5321/7208/7489 verdicts — bool per message, no parsing SPF strings yourself. |
m.plus_task_id |
Task id automatically extracted from the plus-address. |
resp.quota_remaining |
Per-agent monthly budget remaining in USD-equivalent units. |
require_human=True on send |
Returns waiting_approval; the outbound message dispatches after app/dashboard approval. |
API
| Method | Purpose |
|---|---|
PostboxClient.send(to, subject, body, thread_key?, idempotency_key?, require_human?) |
Send an email. Returns SendResult. |
PostboxClient.list_messages(agent_id, direction?, limit?, since?) |
List inbound or outbound messages. Returns list[Message]. |
PostboxClient.read_message(agent_id, message_id) |
Full message with body + verdicts. |
PostboxClient.list_inboxes(agent_id?) |
Provisioned inboxes. |
plus_address(base_inbox, task_id) |
Build base+task@domain. |
parse_plus_address(addr) |
{base, task_id, domain} or None. |
verify_signature(raw_body, signature, secret) |
Timing-safe HMAC-SHA256 check on an inbound webhook. |
parse_inbound_event(raw_body) |
Raw bytes/dict → InboundEvent. |
An AsyncPostboxClient mirrors the same surface on httpx.AsyncClient.
Retries
Retries automatically on 429 and 5xx with exponential backoff and
respect for Retry-After. Default max 3 retries. Tune with
PostboxClient(max_retries=…).
Webhook verification
from ujex_postbox import verify_signature, parse_inbound_event
ok = verify_signature(
raw_body=request.body, # bytes
signature=request.headers["x-ujex-signature"],
secret=os.environ["POSTBOX_INGEST_SECRET"],
)
if not ok:
return Response(status=401)
event = parse_inbound_event(request.body)
if event.injection_score.score > 0.7:
# flag for review, don't let the agent process it yet
quarantine(event)
Framework integrations
Each adapter is an opt-in install that raises a clear ImportError with
install instructions if the framework isn't present.
LangChain
pip install 'ujex-postbox[langchain]'
from ujex_postbox import PostboxClient
from ujex_postbox.integrations.langchain import postbox_tools
client = PostboxClient(device_key="ap_live_...", agent_id="agent-hello")
tools = postbox_tools(client, agent_id="agent-hello")
# hand `tools` to any LangChain agent / graph
LlamaIndex
pip install 'ujex-postbox[llamaindex]'
from ujex_postbox import PostboxClient
from ujex_postbox.integrations.llamaindex import postbox_tools
client = PostboxClient(device_key="ap_live_...", agent_id="agent-hello")
tools = postbox_tools(client, agent_id="agent-hello")
CrewAI
pip install 'ujex-postbox[crewai]'
from ujex_postbox import PostboxClient
from ujex_postbox.integrations.crewai import postbox_tools
client = PostboxClient(device_key="ap_live_...", agent_id="agent-hello")
send_tool, read_tool, list_tool = postbox_tools(client, agent_id="agent-hello")
Core loop
Use Python for the Postbox edge of the golden path: send/receive agent mail,
request human approval with require_human=True, and inspect prompt-injection
signals on inbound messages. Recall memory and owner-scoped Audit are available
through the dashboard, CLI, and TypeScript client while the Python SDK remains
Postbox-focused.
No account yet?
Free tier: 100 sends/month plus approvals, audit, and Recall memory, no card. Sign up at ujex.dev.
License
Apache-2.0
Project details
Release history Release notifications | RSS feed
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 ujex_postbox-0.1.0.tar.gz.
File metadata
- Download URL: ujex_postbox-0.1.0.tar.gz
- Upload date:
- Size: 20.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a5f17efb8a97197e6dab7a56f894e1f42ef802b931d3cccdde9c87430aa2a27c
|
|
| MD5 |
00363b8f77a9eaa16696f19d7ac5af34
|
|
| BLAKE2b-256 |
646621217675903791b7edc29a608963e198668f9536d7dbf21875a1866eb108
|
File details
Details for the file ujex_postbox-0.1.0-py3-none-any.whl.
File metadata
- Download URL: ujex_postbox-0.1.0-py3-none-any.whl
- Upload date:
- Size: 26.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
98445f2a2d580a537acc3c08ce06e8f08cb1f4013cc4407abe0b0b05ca0dc0b5
|
|
| MD5 |
47d499e76d63cd002138a7d061080fd1
|
|
| BLAKE2b-256 |
e13356da5b361ba3f66987cb9db1350889f83abf0ab3a7d4dd325fa9de78b3c8
|