
Openagentemail
io.github.openagentemailPublished by GitHub account openagentemailv0.10.0Updated Oct 24, 2026
Unlimited agent mailboxes — create identities, read/wait for mail, extract OTPs, send email.
Overview
Lets an assistant use an OpenAgentEmail identity to send and read mail, extract OTP codes, and exchange structured task handoffs with other agents.
- What you can do
- The stdio MCP wrapper connects to an OpenAgentEmail API instance and exposes its operations: creating and using agent identities, sending and reading mail, waiting for matching messages, and extracting OTP codes and links. It also supports structured task threads with state history, results, approvals, notifications and optional webhooks. Waits are capped per server setting, and the wrapper can re-arm shorter segments within a requested deadline.
- When to use it
- Use it when agents in different terminals or machines need a shared mailbox and an inspectable way to hand off work, or when an assistant needs to receive email and pull one-time codes. It is also useful if you already run or have access to an OpenAgentEmail instance and want to connect an agent to it.
- Requirements
- Runs locally via npx with Node.js 20 or later. Needs an OpenAgentEmail API base URL in OPENAGENTEMAIL_API_URL and an identity token in OPENAGENTEMAIL_API_KEY, obtained from the instance operator. A reachable API instance is required; the stdio client does not need the mailserver's IMAP/SMTP credentials.
Installation
In SourceWeft
- Open Openagentemail in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
OpenAgentEmail
Open communication and task handoffs for AI agents.
Self-hosted email, task threads, approvals, and webhooks over MCP and REST
—for the agents you already use.
Bring your own agents. Keep control of the work.
Get started · Try a task handoff · Documentation · Architecture · 简体中文
[Apache-2.0 license] [Main branch CI status] [MCP package version, not a whole-stack version]
See it work
Give an agent an address. Send it a task. Read its progress and result in the same thread. OAE keeps the handoff inspectable; your agent's existing harness does the work.
[Task handoff demo cover: requester creates a task, recipient reports working then completed]
Watch the handoff recording (MP4) — about 47 seconds. The video is linked, not embedded inline. Both sides drive real REST calls from a recording scaffold (not a live human clicking the console); frames were captured with headless Chrome + CDP; timestamps use UTC+8 12-hour clock; the pointer and subtitle strip are post-production decoration. Activation is explicit in the recording—do not treat it as proof of automatic wakeup. Reproduce the protocol yourself with the two-identity read-only code-review recipe.
See the existing email and OTP interface
[Existing web dashboard screenshot: an email with its extracted verification code]
This repository image demonstrates the email capability, not an Agent orchestration console. Task-board product images appear under Human visibility below.
Why OpenAgentEmail?
Agents running in different terminals or on different devices need a shared way to communicate: who asked for the work, who received it, what is happening, and what came back. They should not have to share an admin credential or switch to one execution environment just to exchange work.
OAE combines ordinary email with structured, authenticated task threads. Use it as an agent mailbox, an inspectable task handoff layer, or both. Email and OTP workflows remain first-class; the project is not limited to being an email-service alternative.
What you can do today
[Tasks dashboard: "Waiting for you" view — no tasks in input-required for the selected period]
[Completed task view with state history and structured result]
These are real product screenshots from a controlled capture (anonymized). They show inspectability, not that a notification was consumed or an approved action executed.
REST, HTTP MCP and the stdio MCP wrapper expose these operations. Optional task leases provide recipient claim/renew/release; they do not make external side effects exactly-once. See the tool reference.
Quickstart
Already have an instance?
Ask its operator for your identity address and appropriate identity token, then connect your agent. You do not need to deploy another mailserver. Complete a first task handoff, or send a test email to your identity and confirm you can read it.
Deploy a new instance
Start the guided setup:
The setup CLI guides deployment and client configuration. Choose the mail backend that fits your environment:
Keep the API's localhost binding unless you deliberately configure an SSH tunnel or HTTPS reverse proxy. Mail certificates and HTTPS for the API are separate concerns. Do not publish a bare HTTP API carrying tokens.
After deployment, verify the path you actually chose:
Bundled mailserver. This stack owns mail.$DOMAIN, the mail DKIM selector, and
TLS on ports 465/993. Run the doctor against that layout:
It checks DNS, port access, certificates and notification prerequisites for the bundled stack. It still does not log in over IMAP/SMTP or send a round-trip email.
API-only (your own mail provider). Skip deploy/doctor.sh — it assumes the
bundled mail host and will report false failures for a different MX/DKIM setup.
Instead: confirm /healthz returns healthy, confirm your IMAP/SMTP credentials work
for the catch-all mailbox, then send a real message to an identity and read it back.
Only then try the task recipe. A healthy /healthz alone proves the HTTP process is
alive, not that mail delivery works.
Existing api-data volume: one-time non-root migration (#93)
The API runtime image runs as the bun user (uid/gid 1000), not root.
New named volumes inherit ownership from the image's /app/data directory
and need no host-side fix. Existing production volumes that were written
while the API ran as root stay root-owned; the new non-root process cannot
write them until you migrate once.
Order is fail-fast by design: migrate the volume before rolling the new image. Shipping the new image first will refuse to start (or fail on first write) until ownership is fixed — that is intentional, not a silent fallback.
- Take a backup of the project-scoped volume (example project name
openagentemail→ volumeopenagentemail_api-data; API-only stacks use their-p/COMPOSE_PROJECT_NAMEprefix, e.g.oae-alpha_api-data). - Stop writers that mount the volume (at minimum the
apiservice; full stack: also stop anything else writingapi-dataduring the window) — and keep them down until they are recreated in step 6. Stopping is not enough on its own: the migration only counts once every old container is gone for good.restart≠ recreate — a root container that comes back up (crashed-and-restarted, or brought up by habit) keeps writing and silently recreates volume files asroot:root, rolling your chown back without any error. If a writer came back up for any reason, stop it and redo step 3 before proceeding. - One-shot chown to the runtime user:
- Spot-check ownership before bringing services back:
- Read back the migration on the volume — must pass:
- Pull/build the new images, then verify the API image declares the
runtime user before starting anything. Build the whole project
(
docker compose buildwith no service name) — or at minimumapiandntfy-provisiontogether: they share one Dockerfile, and the--force-recreatebelow re-runs the one-shot ntfy-provision container too, so it must come from the same non-root image batch. A stale root-based provision image re-running here would write the volume as root and roll your migration back — the same failure this runbook exists to prevent.
Only then start everything (docker compose up -d --force-recreate
or your usual deploy path).
Do not reverse this order. Production chown is a deploy-window operation; it is not performed by the image entrypoint.
Deploy-window recreate gotchas (measured 2026-09-21)
--force-recreate <service>follows the dependency chain. Measured on the reference host: recreatingapialso recreatedmailserveralongapi→mailserver→provision(andntfypullsntfy-provision) — healthy, ~11s, no loss, but unintended. To recreate only the named services, add--no-deps; full-project builds keep the plain form.- Measure override attribution — do not assume it. Before editing
or removing any override, run
docker compose configagainst three configurations: base alone, base + each override, and compare the resolved output field by field. On the reference host (2026-09-21) this distinguished two siblings:docker-compose.override.ymlwas a zero-contribution no-op (its patches had long been absorbed into the base file) and was removed with a timestamped backup, whilecompose.override.yamlis live and must be kept (adds the loopback binding and widens allowed ports). A "Found multiple override files" warning at recreate time is the cue to run this check. Scope note: override auto-merging happens only on default-file invocations — deployments selecting files explicitly (e.g. API-onlydocker compose -f compose.api-only.yaml ...) auto-merge no override at all and must pass every override explicitly.
ntfy non-root upgrade (#278)
ntfy now runs as UID 1000 and listens on container port 2587. If an
existing deploy previously ran ntfy as root, chown its data before
up -d — otherwise ntfy fails to start and the API stays down (depends_on
healthy):
Then docker compose up -d (recreate ntfy and api). A prior full-volume
#93 migration already covers /data/ntfy; re-run only if that subtree is
still root-owned.
Connect your agent
Choose the right credential
These are current API semantics, not a proposal for new scopes. Full identity permissions are not admin permissions. Only an operator should create/list/manage identities. Keep admin keys out of agent client configurations. See credential setup.
Local stdio MCP
The published MCP client requires Node.js 20+, matching its package contract. The API server runs on Bun inside its container. A generic local-client configuration is:
Use localhost only for an API on the same host or behind a local SSH tunnel. For a remote instance use its HTTPS base URL. Protect the client configuration; do not commit tokens. The stdio client never needs the mailserver's IMAP/SMTP credentials.
Remote HTTP MCP
Clients supporting remote MCP can connect directly to the instance's /mcp
endpoint without installing the stdio package. Configure a public HTTPS origin and
follow the client's supported Bearer/OAuth flow. OAuth grants do not have the same
mutation permissions as admin or direct identity credentials. Use the
client guide; protocol support is not a claim of automatic
wakeup or a vendor partnership.
The MCP reference covers all registered tools,
permissions and wait semantics. Each server wait is capped by MCP_MAX_WAIT_SECONDS
(default 60 seconds, configurable from 1 to 600). The MCP mail client can re-arm
shorter segments within its requested total deadline; task waits are one capped turn.
A wait timeout is not a failed job. After an uncertain create outcome, check the returned task ID/history rather
than blindly creating another task.
How it works
Tasks are reconstructed from authenticated mail records. Local files also hold operational state, including an optional pending lease journal. Execution stays in the agent's own runtime—OAE does not run the model. This is a single-process service with background loops, not a distributed worker runtime.
The core does not require Orca. The checked-in webhook-wake example currently targets Orca; it is not a universal replacement adapter. Already-recorded pending webhook deliveries can be recovered, but the watcher does not replay all mail that arrived while the API was stopped. Consumers should reconcile their task/mail state on startup or reconnect rather than treating a notification as the only record of work.
Read the current architecture and data ownership for the SMTP/IMAP visibility overlay, task state and notification boundaries.
Deployment and boundaries
Own the data path, not just the server. A self-hosted instance avoids a required OAE SaaS control plane. An external mailbox provider, SMTP relay, archive recipient or notification destination can still receive data according to your configuration. Mail returned to a remote model/client also leaves the server. Review that path before exposing credentials or message content.
Capacity and limits are operational choices. There is no per-identity software
licensing charge. Mailbox capacity, provider policy, disk, memory and configurable
rate limits still apply (sending defaults to 20 messages/hour per identity; the API rebuilds that hourly window from send-log.jsonl on startup — queued rows plus failed rows the SMTP server answered — and a send whose log line was lost is not counted).
Ordinary mail defaults to 30-day retention; task-marked mail is excluded from that
sweeper. Back up the mail store, DATA_DIR and stable signing secrets together.
Seen is shared state. Marking a message read affects other mailbox consumers; it is not a private agent acknowledgement. Use a consumer-specific cursor and periodic reconciliation for independent processing. Reading alone does not mark mail seen.
Optional leases: defaults and rollout boundaries
TASK_LEASES_ENABLED defaults to false. When enabled, use exactly one API process
per mailbox. Claim/renew/release require the managed recipient's identity, not an
admin impersonation. Do not enable multiple API writers against the same state.
- Optional
TASK_LEASES_EXPIRY_AUDIT_M3(default false) decouples reclaim from expiry-audit SMTP; late matching expiry receipt tolerance is always on. - Optional
TASK_LEASES_OVERLAY_BOUND(default false) stops public list/detail replay of unindexed lease overlay events after 15 minutes. - Optional
TASK_LEASES_PENDING_JOURNAL(default false, requiresTASK_LEASES_ENABLED) preserves pending generation fences across restart and records or defers expiry-audit work. - Even with journal off (production default),
claimreturns 409lease_overlay_pending_indexwhile a fresh (≤15 min)release/renewhas been SMTP-accepted but not yet absorbed into the durable rebuild. Callers should retry after indexing. If the receipt is permanently lost, the fence ages out after 15 minutes (mirrorsTASK_LEASES_OVERLAY_BOUND) and claim proceeds; divergence is contained by the #305 read-side degrade (#308).
Production expiry-audit emission remains hard-disabled; these flags do not enable
it. Read the journal operating guide before provisioning
or enabling journal writes. Provisioning is not a wipe/recovery procedure. After a
claim_lost tombstone exists, rollback to an old reader is unsafe. Leases do not
undo external file changes, commits or other side effects.
Examples and documentation
Framework examples and local fixtures are not evidence of a production end-to-end run. Their own READMEs identify which paths use fake services and which require an explicit live invocation.
Direction and contribution
Bring your own agents. Keep work inspectable. Own your infrastructure. Build the handoff, not another runtime.
The next direction is simpler connection to existing working environments and clearer recovery/operating guidance—not a promise of a general scheduler, shared workspace manager, global federation or automatic code execution. Current capabilities are listed above; release history belongs in CHANGELOG.md. The npm badge tracks the MCP package, not a unified server/deployment version.
See #251 for the README refresh and remaining live-demo/website follow-ups. The website repository owns public-site presentation and documentation.
Issues and PRs are welcome. Read CONTRIBUTING.md: substantial work starts with an issue; independent review and green CI are required before merge. Documentation changes should track actual code, not anticipated capabilities.
Operator shortcuts and advanced deployment
Using your own mail server
Already have a mail provider for your domain? Run the API by itself with
compose.api-only.yaml, connected to that provider's
catch-all mailbox. The external mail server guide
covers the required catch-all setup, Portainer deployment, SMTP sender limits,
and TLS certificate verification.
The standalone default project name is openagentemail. If the full
compose.yaml stack also runs on the same host, the API-only stack must not
share that default project: give it an explicitly different -p value or
COMPOSE_PROJECT_NAME so the two stacks cannot adopt each other's resources.
To run multiple API-only instances on one host, give every instance its own
environment file, unique Compose project, and host API_PORT. The API always
listens on port 3100 inside its container; API_PORT changes only the host-side
mapping. For example:
You may set a unique COMPOSE_PROJECT_NAME for each command instead of using
-p. The project names make Compose generate distinct container names and
project-scoped named volumes. Each instance must have independently generated
API_KEYS and TASK_SIGNING_SECRET values. Use distinct API_PORT values,
separate data volumes and the intended independent mailbox/provider boundary;
this is not a multi-writer recipe. Keep populated files outside the repository.
Read mail in a browser
Open /ui through localhost, an SSH tunnel or HTTPS and log in with an appropriate
token. Ordinary sessions and persisted Trust this device sessions have different
lifetimes; restarting the API does not discard every trusted session. See
UI access and sessions.
The dashboard UI supports en / es / ja / ko / zh-CN via the Settings language
selector (oa_lang cookie); terminology follows docs/i18n-glossary.md.
Overview counts are a bounded window, not lifetime totals. Cache timing, unknown counts and scan limits are described in the operator guide.
Multi-domain support
DOMAIN plus EXTRA_DOMAINS defines domains managed by one instance. Explicit
identities with the same localpart can coexist on different configured domains;
full-address duplicates cannot. Additional domains still require provider/MTA
routing and DNS/DKIM setup. This is not independent-instance federation. See
multi-domain operations.
Public mail TLS and renewal are opt-in; HTTPS for the API needs its own trusted reverse proxy or tunnel.
Optional compliance archive:
ALWAYS_BCC is off by default and creates an additional off-domain data recipient.
Self-host for control of deployment, data paths and policies—not a promise of zero cost, unlimited hardware capacity or immunity from upstream provider policies.
Resource planning depends on the workload; this README does not publish an undated benchmark or a VPS-price guarantee.
OAE is an open-source option for agent email and task handoffs. Detailed vendor comparisons need dated primary sources; the old unchecked feature matrix is retired.
License
Source: README.md at commit b2d4d9c
Tools
0Version history
4- v0.10.0LatestSep 29, 2026
- v0.9.0Sep 22, 2026
- v0.8.0Sep 20, 2026
- v0.7.3Sep 16, 2026
Score
50% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
- Reached in the last 30 days25 pts
Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.
- Auth declared10 pts
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
- Tools listed15 pts
Answer tools/list without a credential, or ship a package that starts in a sandbox without one.
- DescriptionRequired15 pts
- Logo10 pts
- Documentation15 pts
- License10 pts