
Company News
Jerod Santo Joins Socket as Head of Media
Allow myself to introduce... myself.
@agenticmail/api
Advanced tools
REST API server for AgenticMail — email, SMS, and phone call-control endpoints for AI agents
The API server for AgenticMail — the part that lets AI agents (and humans) talk to the email and SMS system over the network.
This package runs a web server that handles everything: sending email and SMS, reading inboxes, managing agents, phone number access, real-time notifications, inter-agent messaging, spam filtering, outbound security scanning, and gateway configuration. Every feature in AgenticMail is accessible through this API.
GET / POST / DELETE /agents/me/memory/threads/:t — agent-key scoped; each agent only ever touches its own memory file.GET /agents/me/thread-id?uid=42&folder=INBOX — resolves the stable subject-only thread id for a message UID, looking up the canonical root via the dispatcher's ThreadCache when available.wake default flipped to "To: only". POST /mail/send, POST /drafts/:id/send, POST /templates/:id/send, and the pending-outbound persistence path all derive the implicit allowlist from local recipients on the To: field when wake is omitted. CC'd local agents receive the mail without waking. New helper deriveDefaultWakeList(to) exported from routes/mail.ts. Opt back into the old behaviour with wake: 'all'.POST /tasks/assign and the long-poll POST /tasks/rpc accept an optional outputSchema field (JSON Schema, draft-7 subset). The schema is persisted on the task row via migration 014_task_output_schema.sql and is rendered into the worker's wake prompt. POST /tasks/:id/result validates against the schema before accepting; mismatches return 400 with a flat schemaErrors: [{ path, message }] list. Validator lives at src/lib/schema-validator.ts (hand-rolled, no ajv dep) and supports type, required, properties, items, enum, additionalProperties: false, minLength/maxLength, minimum/maximum. Tasks without a schema keep the v0.8.x behaviour — fully back-compat.POST /mail/messages/:uid/star with { starred: boolean, folder?: string }. Maps to IMAP's \Flagged flag — same on-disk bit Gmail's star uses.POST /dispatcher/worker-heartbeat, GET /dispatcher/worker-log/:id. Combined with the dropped 30-min active TTL, workers can run for hours; staleness is a flag, not an eviction trigger.packages/api/public/ — Gmail two-column layout, official Claude + AgenticMail logos, hash router (#/folder/<id>, #/m/<uid>), folder auto-discovery (works on Stalwart / Gmail / Outlook / macOS Mail conventions), 2-line preview rows, mobile-responsive sidebar, draft autosave, vector icon library.packages/api/public/ ships a proper two-column Gmail layout (sidebar with Compose + folders / content pane) served by express.static at the API root. Every emoji replaced with an inline 24×24 vector icon library (public/js/icons.js). HTML shell + dedicated styles.css + 14 modular ES module JS files under public/js/. Hash router (#/inbox, #/m/<uid>), search with from: / subject: operators, real-time SSE updates, browser notifications. Run via agenticmail web from the CLI.POST /mail/send — accept a wake parameter (array of agent names or comma-separated string). The API normalises it, sets an X-AgenticMail-Wake header on the outgoing SMTP envelope, AND surfaces it as wakeAllowlist on the SSE event so the dispatcher can decide which CC'd recipients to actually give a Claude turn.routes/mail.ts — normalizeWakeList, wakeHeaders, and pushLocalRecipientWakes so every send path (/mail/send, /templates/:id/send, /drafts/:id/send, /mail/pending/:id/approve) uses the same primitives.GET /system/events — master-auth stream that emits account_created / account_deleted / worker_started / worker_finished events. Powers the dispatcher's zero-wait wake on newly-created agents and the check_activity MCP tool.GET /dispatcher/activity returns the currently-active and recently-finished workers; POST /dispatcher/worker-{started,finished} lets the dispatcher push updates. Master-auth.npm install @agenticmail/api
Requirements: Node.js 22+ (uses Node's built-in node:sqlite, no native compilation), @agenticmail/core@^0.7.0, Stalwart Mail Server running (via Docker / Colima).
Default listen address: http://127.0.0.1:3829. The port changed from 3100 to 3829 in 0.7.x to avoid clashes with common dev-tool defaults (Grafana Loki, Express scaffolds, etc.). Override via AGENTICMAIL_API_PORT env var or api.port in ~/.agenticmail/config.json.
The API server is the central hub. It sits between agents (or any client) and the email infrastructure. Rather than agents connecting to IMAP/SMTP directly, they make simple web requests to this server, which handles all the complexity behind the scenes.
agenticmail start) — powers every command in the CLI@agenticmail/mcp) — translates AI tool calls into API requests@agenticmail/openclaw) — same thing but for the OpenClaw framework@agenticmail/claudecode) — surfaces every AgenticMail agent as a callable subagent and bridges inbound mail/tasks to Claude-powered workers via a dispatcher daemon. The API auto-mounts integration routes under /api/agenticmail/integrations/claudecode/* when @agenticmail/claudecode is installed as an optional dependency.When @agenticmail/claudecode is installed alongside the API server, three additional routes light up:
GET /api/agenticmail/integrations/claudecode/status
POST /api/agenticmail/integrations/claudecode/install
POST /api/agenticmail/integrations/claudecode/uninstall
These are mounted before the master-key auth middleware on purpose — a fresh Claude Code session that doesn't yet have AgenticMail wired up has no way to know the master key, so requiring it would defeat the "agent installs itself" use case. The API binds to 127.0.0.1 by default, so anything that can reach these endpoints can already read ~/.agenticmail/config.json — the unauthenticated install endpoint doesn't widen the attack surface beyond that. If you bind the API to a non-loopback interface, put auth or a firewall in front of it (same caveat as every other unauthenticated route on the server, e.g. /health).
The API uses two types of keys, and the distinction matters a lot for security.
The master key is the admin password. It is set once during setup and never changes. The person holding the master key is considered the owner — the human who controls the system. The master key can do everything: create and delete agents, configure the email gateway, and critically, approve or reject blocked outbound emails.
Each AI agent gets its own key when created. An agent key lets that agent do things scoped to itself: read its own inbox, send email (subject to security scanning), manage its own contacts, drafts, rules, and so on. An agent cannot access another agent's inbox, and cannot approve its own blocked emails — that is reserved for the human owner.
When an AI agent tries to send an email that the outbound guard flags as potentially sensitive (containing passwords, personal information, internal system details, etc.), the email gets blocked and stored for review. Only the person with the master key can approve or reject it. This prevents an AI from leaking sensitive data without human oversight.
The key comparison uses timing-safe SHA-256 hashing so that the time it takes to check a key doesn't reveal any information about what the correct key is. This is a standard security practice to prevent timing attacks.
When an agent sends an email, several things happen before it actually goes out:
Outbound security scan — the email is checked against 34+ rules looking for leaked passwords, API keys, personal information (SSN, credit card numbers, phone numbers), internal system URLs, database connection strings, and more. Each match is scored by severity (critical, high, medium, low).
If the email is clean — it goes out immediately. If a gateway (Gmail relay or custom domain) is configured, the email routes through that. Otherwise it sends via the local Stalwart mail server. A copy is saved to the agent's Sent folder.
If the email is flagged — it gets stored in a pending queue. The owner receives a notification email with the full content of the blocked email, the security warnings that triggered, and instructions on what to do.
The owner decides — The owner can approve or reject by calling the API with their master key, using the interactive shell's /pending command, or simply replying to the notification email with words like "approve", "yes", "lgtm", "go ahead", "send", or "ok". Replying with "reject", "no", "deny", "cancel", or "block" discards the email. The relay polling system automatically detects these replies and acts on them.
Master bypass — The owner (master key) can send an email with allowSensitive: true to bypass all security scanning entirely. Agent keys cannot use this bypass — even if an agent passes the flag, the guard still runs.
Agents can set a display name through their metadata (the ownerName field). When an agent sends email, the From header shows something like "secretary from John" <secretary@yourdomain.com>. Without a display name, it just shows the agent's name.
Emails can include file attachments. The API accepts them as objects with a filename, content type, and content (as a Buffer or base64 string). The outbound guard also checks attachments for risky file types.
Agents can read their own inbox in several ways:
List inbox — shows message metadata (who it's from, subject, date, read/unread flags, size) with pagination. Default 20 messages per page, up to 200.
Digest view — same as the inbox list but includes a preview of each email's body (the first 200 characters by default, configurable up to 500). Useful for getting a quick sense of what each email says without fetching the full body.
Read a specific message — fetches the complete email: full headers, text body, HTML body, attachment metadata, and a security analysis. The security analysis includes a spam score, whether it's classified as spam or just a warning, the top threat category if any, which rules matched, and whether any invisible Unicode characters or hidden HTML were detected and sanitized.
Search — find emails by sender, recipient, subject, body text, date range, or read/unread status. Can also search the connected relay account (Gmail/Outlook) if one is configured.
Every email from an external source gets scored when you read it. The spam scoring engine uses 47 rules across 9 categories (prompt injection, social engineering, data exfiltration, phishing, header anomalies, content spam, suspicious links, authentication issues, and attachment risks). Internal emails (sent between agents on the same system) skip scoring entirely since they are trusted.
If the system detects invisible Unicode characters (zero-width spaces, invisible separators, bidirectional text tricks) or hidden HTML (tiny fonts, invisible text, elements positioned off-screen), it sanitizes them and tells you what it found.
Agents can open a persistent connection to receive instant notifications about new emails, deleted emails, and flag changes. This uses Server-Sent Events (SSE), which is just a long-lived HTTP connection that the server pushes updates through.
When a new email lands in an agent's inbox, the system does several things in real-time:
Relay detection — if the email came through the relay gateway (Gmail/Outlook), it's marked as external even if the sender address looks like a local agent. This prevents relay-forwarded emails from bypassing the spam filter.
Spam scoring — external emails are scored. If the score exceeds the spam threshold, the email is automatically moved to the Spam folder and the notification event includes spam details. If it's a warning (elevated but not spam), the event includes the warning info but the email stays in the inbox.
Route classification — the event is tagged with a route class such as ignore_spam, ignore_newsletter, archive_automated, project_update, deal_escalation, or agent_instruction. The route also includes the suggested action and whether a human gate is required.
Rule evaluation — after spam filtering, the system checks the agent's custom email rules. Rules are checked in priority order and the first match wins. A rule can auto-mark the email as read, delete it, or move it to a specific folder.
Notification sent — the event is pushed to all of the agent's connected SSE streams.
Each agent can have up to 5 simultaneous SSE connections. This prevents resource exhaustion — each connection holds an open IMAP connection to the mail server. A keepalive ping is sent every 30 seconds to prevent timeouts.
Every spam score is recorded in the spam_log table with the full analysis. These logs are automatically cleaned up after 30 days.
Only the master key can create new agents. Each agent gets a name, an email address on the local domain, an API key, and a role. The first agent created is automatically marked as "persistent" (won't be deleted during cleanup).
Agent names must be alphanumeric (plus dots, hyphens, and underscores), up to 64 characters.
Agents have an activity tracker. Every time an agent makes an API call, its last_activity_at timestamp is updated (throttled to at most once per 60 seconds to avoid database churn). This lets the system identify inactive agents.
The /accounts/cleanup endpoint finds agents that haven't been active for a configurable number of hours (default 24) and deletes them — unless they're marked as persistent. You can do a dry run first to see who would be deleted.
When an agent is deleted, its emails can optionally be archived first. The deletion creates a report recording which agent was deleted, when, why, and by whom. Past deletion reports are kept and can be reviewed later.
Deleting the last remaining agent is not allowed — the system always needs at least one.
Any authenticated user (agent or master) can look up the directory — a simple list of all agents with their name, email address, and role. This lets agents discover each other for inter-agent communication.
Agents can assign work to each other through a built-in task system.
Any authenticated user can assign a task to an agent. You specify the assignee (by name), a task type (like "lookup" or "analyze"), and an optional payload with details. The target agent is notified three ways:
A task goes through states: pending (just assigned) → claimed (agent accepted it) → completed or failed. Any agent that knows a task's ID can claim it — this supports sub-agent architectures where a parent agent's tasks are claimed by a specialized child agent.
Tasks can have an expiration time. The payload and result are stored as JSON.
For cases where you need an answer right away, there's an RPC endpoint. It assigns a task and then holds the HTTP connection open, waiting for the target agent to complete it. The connection stays open for up to 5 minutes (configurable from 5 seconds to 300 seconds).
The waiting is efficient — when the target agent submits a result, the server instantly resolves the waiting connection. There's also a polling fallback (every 2 seconds) in case the instant notification is missed.
If the task isn't completed before the timeout, you get back a timeout response with the task ID so you can check on it later.
This is one of the most important security features. Here is how it works end-to-end:
Agent tries to send an email — the outbound guard scans it and finds sensitive content (a password, an API key, a credit card number, whatever).
Email is blocked — stored in the pending_outbound table with the full email content, the security warnings, and a summary.
Owner is notified — a notification email is sent to the owner's relay address (e.g., their Gmail). The email includes the full content of the blocked message, all security warnings, the pending ID, and instructions: "Reply approve to send, or reject to discard."
Owner responds — the owner can:
POST /mail/pending/:id/approve or /reject with the master key/pending in the interactive shellEmail is sent or discarded — if approved, the system re-sends the email through the gateway (or local SMTP). If rejected, it's marked as rejected and discarded.
Agent cannot self-approve — even if an agent has the pending email's ID and tries to call the approve endpoint, the server rejects the request with a 403 error. Only the master key works.
When the relay gateway (Gmail/Outlook) is configured, the system continuously polls the relay inbox for new messages. This polling runs on an exponential backoff schedule (starting at 30 seconds, growing to a cap of 5 minutes, and resetting when new mail arrives). This means the system automatically picks up approval replies within a few minutes at most.
This also means the agent effectively has a "cron job" — the polling loop keeps running in the background, checking for responses and delivering them to the right agent's local inbox. The agent doesn't need to do anything special; replies just show up.
For domain mode (when you have a custom domain like @yourdomain.com), incoming internet email arrives through a Cloudflare Email Worker. The worker forwards the raw email to the API's inbound webhook endpoint.
The webhook:
X-Inbound-Secret header), not a Bearer tokenEach agent gets a full set of email management tools:
Agents can create custom IMAP folders, list all folders, and move messages between them. Folder names are validated (max 200 characters, no special IMAP characters).
A personal address book per agent. Contacts have a name, email address, and optional notes. Adding a contact with an existing email updates the existing entry.
Save email drafts for later editing and sending. Drafts store the full email (to, subject, body, CC, BCC, threading headers). You can send a draft directly, which validates it has a recipient, sends it, and then deletes the draft.
Reusable email signatures in both text and HTML format. One signature can be marked as the default. Setting a new default automatically unsets the previous one.
Reusable email templates with variable substitution. Templates have a name, subject line, and body. When sending from a template, you provide the recipient and a variables object — the system replaces {{ variableName }} patterns in the subject and body with your values.
Create colored tags and apply them to messages. Tags can be listed, created, deleted, and attached to or removed from specific messages. You can look up which messages have a specific tag, or which tags are on a specific message.
Automated rules that run when new email arrives. Each rule has conditions (match on sender, recipient, subject, or attachment presence) and actions (mark as read, delete, or move to folder). Rules have a priority number — higher priority rules are checked first, and the first match wins. Rules can be enabled or disabled.
Schedule emails to be sent at a future time. The system supports many time formats:
2026-02-14T10:00:00Zin 30 minutes, in 2 hourstomorrow 8am, tomorrow 2pmnext monday 9am, next friday 2pm02-14-2026 3:30 PM ESTtonight, this evening (sends at 8 PM)The scheduled sender checks every 30 seconds for emails whose send time has arrived, then sends them through the gateway or local SMTP.
For efficiency, agents can perform operations on multiple messages at once:
The gateway connects the local mail system to the internet. There are two modes:
Uses an existing Gmail or Outlook account. Easy to set up — just provide your email and an app password. Agent emails go out through your account as sub-addressed emails (like yourname+agentname@gmail.com). Incoming replies are polled and delivered to the right agent.
Uses a custom domain with Cloudflare for DNS, email routing, and tunneling. More professional — agents get addresses like secretary@yourdomain.com. Requires a Cloudflare account and API token. The system can set up DNS records, email routing rules, and a Cloudflare Tunnel automatically.
Domain mode also supports a Gmail relay for outbound sending, which means you get the professional addresses but send through Gmail's reliable infrastructure.
After configuration, you can send a test email through the gateway to verify everything is working.
The API server manages connections to the mail server efficiently:
The API server runs two background services:
Runs every 30 seconds. Checks for scheduled emails whose send time has arrived, sends them, and updates their status. Also performs housekeeping: cleans up delivery deduplication records and spam logs older than 30 days.
On startup, the server resumes any previously configured gateway (relay polling or domain mode tunnel). This means restarting the API server doesn't break the email gateway — it picks up right where it left off.
When the server receives a shutdown signal (Ctrl+C or SIGTERM):
The API returns standard HTTP status codes:
JSON parse errors (malformed request bodies) return a clear 400 error rather than a confusing 500.
| Variable | Required | Default | Description |
|---|---|---|---|
AGENTICMAIL_MASTER_KEY | Yes | — | Admin API key (the human owner's key) |
AGENTICMAIL_API_PORT | No | 3829 | Port for the API server |
STALWART_URL | No | http://localhost:8080 | Stalwart mail server admin URL |
STALWART_ADMIN_USER | No | admin | Stalwart admin username |
STALWART_ADMIN_PASSWORD | No | changeme | Stalwart admin password |
SMTP_HOST | No | localhost | SMTP server host |
SMTP_PORT | No | 587 | SMTP server port |
IMAP_HOST | No | localhost | IMAP server host |
IMAP_PORT | No | 143 | IMAP server port |
AGENTICMAIL_INBOUND_SECRET | No | (built-in default) | Shared secret for the inbound email webhook |
AGENTICMAIL_DEBUG | No | — | Set to any value to enable verbose per-message logging |
/gateway/relay actually opens upThe
POST /gateway/relayendpoint (the oneagenticmail setup-emailcalls) makes every sub-agent publicly reachable from the internet via plus-addressing. This is by design — agents that can only email each other aren't very useful for talking to real people — but the implications surprise some operators:
your-relay+secretary@gmail.com, your-relay+kepler@gmail.com, etc. and the corresponding agent's AgenticMail inbox receives the message. The +sub part is not a secret.@localhost mail. The API publishes the same SSE new-mail event regardless of source; the host integration (@agenticmail/claudecode, @agenticmail/codex) spawns a worker turn either way.your-relay+claudecode@gmail.com / your-relay+codex@gmail.com routes to handleBridgeMail in the dispatcher, which uses the host SDK's resume option to wake the operator's last session headlessly. If that fails it falls through to the bridge-escalation email configured via setup_operator_email.wake-budget guard in dispatcher.handleEvent (automatic, default cap per minute per agent), the built-in relay-level spam filter (runs before publishing the SSE event), and metadata.host-based fencing for agents that should stay internal-only.MIT - Ope Olatunji (@ope-olatunji)
FAQs
REST API server for AgenticMail — email, SMS, and phone call-control endpoints for AI agents
The npm package @agenticmail/api receives a total of 218 weekly downloads. As such, @agenticmail/api popularity was classified as not popular.
We found that @agenticmail/api demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Company News
Allow myself to introduce... myself.

Research
/Security News
A Twitch browser extension on Chrome and Firefox forwards users’ live OAuth session tokens through proxies controlled by a Russian bot service.

Security News
Anthropic found biased reasoning and recklessness drove Claude Mythos 5 to publish malware on PyPI and compromise a security vendor.