@agenticmail/api 0.2.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +35 -0
- package/README.md +370 -0
- package/REFERENCE.md +1314 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3248 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ope Olatunji (https://github.com/ope-olatunji)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
AgenticMail - Email infrastructure for AI agents.
|
|
26
|
+
|
|
27
|
+
Project: https://github.com/agenticmail/agenticmail
|
|
28
|
+
Author: Ope Olatunji
|
|
29
|
+
GitHub: https://github.com/ope-olatunji
|
|
30
|
+
|
|
31
|
+
This software includes components for programmatic email management,
|
|
32
|
+
SMTP/IMAP integration, MCP server tooling, Cloudflare gateway orchestration,
|
|
33
|
+
and OpenClaw plugin infrastructure. All packages within this monorepo
|
|
34
|
+
(@agenticmail/core, @agenticmail/api, @agenticmail/mcp, @agenticmail/openclaw,
|
|
35
|
+
and agenticmail) are covered under this license.
|
package/README.md
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
# @agenticmail/api
|
|
2
|
+
|
|
3
|
+
The API server for [AgenticMail](https://github.com/agenticmail/agenticmail) — the part that lets AI agents (and humans) talk to the email system over the network.
|
|
4
|
+
|
|
5
|
+
This package runs a web server that handles everything: sending email, reading inboxes, managing agents, real-time notifications, inter-agent messaging, spam filtering, outbound security scanning, and gateway configuration. Every feature in AgenticMail is accessible through this API.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @agenticmail/api
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**Requirements:** Node.js 20+, `@agenticmail/core`, Stalwart Mail Server running (via Docker)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## What This Package Does
|
|
18
|
+
|
|
19
|
+
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.
|
|
20
|
+
|
|
21
|
+
### Who talks to the API
|
|
22
|
+
|
|
23
|
+
- **AI agents** — send and receive email, check inboxes, claim tasks
|
|
24
|
+
- **The interactive shell** (`agenticmail start`) — powers every command in the CLI
|
|
25
|
+
- **The MCP server** (`@agenticmail/mcp`) — translates AI tool calls into API requests
|
|
26
|
+
- **OpenClaw sub-agents** (`@agenticmail/openclaw`) — same thing but for the OpenClaw framework
|
|
27
|
+
- **Your own code** — any HTTP client can use the API
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## How Authentication Works
|
|
32
|
+
|
|
33
|
+
The API uses two types of keys, and the distinction matters a lot for security.
|
|
34
|
+
|
|
35
|
+
### Master Key
|
|
36
|
+
|
|
37
|
+
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**.
|
|
38
|
+
|
|
39
|
+
### Agent Keys
|
|
40
|
+
|
|
41
|
+
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.
|
|
42
|
+
|
|
43
|
+
### Why This Matters
|
|
44
|
+
|
|
45
|
+
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.
|
|
46
|
+
|
|
47
|
+
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.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Sending Email
|
|
52
|
+
|
|
53
|
+
When an agent sends an email, several things happen before it actually goes out:
|
|
54
|
+
|
|
55
|
+
1. **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).
|
|
56
|
+
|
|
57
|
+
2. **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.
|
|
58
|
+
|
|
59
|
+
3. **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.
|
|
60
|
+
|
|
61
|
+
4. **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.
|
|
62
|
+
|
|
63
|
+
5. **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.
|
|
64
|
+
|
|
65
|
+
### Display Names
|
|
66
|
+
|
|
67
|
+
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.
|
|
68
|
+
|
|
69
|
+
### Attachments
|
|
70
|
+
|
|
71
|
+
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.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Reading Email
|
|
76
|
+
|
|
77
|
+
Agents can read their own inbox in several ways:
|
|
78
|
+
|
|
79
|
+
- **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.
|
|
80
|
+
|
|
81
|
+
- **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.
|
|
82
|
+
|
|
83
|
+
- **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.
|
|
84
|
+
|
|
85
|
+
- **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.
|
|
86
|
+
|
|
87
|
+
### Spam Protection on Read
|
|
88
|
+
|
|
89
|
+
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.
|
|
90
|
+
|
|
91
|
+
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.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Real-Time Notifications
|
|
96
|
+
|
|
97
|
+
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.
|
|
98
|
+
|
|
99
|
+
### What happens when a new email arrives
|
|
100
|
+
|
|
101
|
+
When a new email lands in an agent's inbox, the system does several things in real-time:
|
|
102
|
+
|
|
103
|
+
1. **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.
|
|
104
|
+
|
|
105
|
+
2. **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.
|
|
106
|
+
|
|
107
|
+
3. **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.
|
|
108
|
+
|
|
109
|
+
4. **Notification sent** — the event is pushed to all of the agent's connected SSE streams.
|
|
110
|
+
|
|
111
|
+
### Connection limits
|
|
112
|
+
|
|
113
|
+
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.
|
|
114
|
+
|
|
115
|
+
### Spam logging
|
|
116
|
+
|
|
117
|
+
Every spam score is recorded in the `spam_log` table with the full analysis. These logs are automatically cleaned up after 30 days.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Managing Agents
|
|
122
|
+
|
|
123
|
+
### Creating Agents
|
|
124
|
+
|
|
125
|
+
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).
|
|
126
|
+
|
|
127
|
+
Agent names must be alphanumeric (plus dots, hyphens, and underscores), up to 64 characters.
|
|
128
|
+
|
|
129
|
+
### Agent Lifecycle
|
|
130
|
+
|
|
131
|
+
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.
|
|
132
|
+
|
|
133
|
+
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.
|
|
134
|
+
|
|
135
|
+
### Deleting Agents
|
|
136
|
+
|
|
137
|
+
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.
|
|
138
|
+
|
|
139
|
+
Deleting the last remaining agent is not allowed — the system always needs at least one.
|
|
140
|
+
|
|
141
|
+
### Agent Directory
|
|
142
|
+
|
|
143
|
+
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.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Inter-Agent Tasks
|
|
148
|
+
|
|
149
|
+
Agents can assign work to each other through a built-in task system.
|
|
150
|
+
|
|
151
|
+
### Assigning Tasks
|
|
152
|
+
|
|
153
|
+
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:
|
|
154
|
+
|
|
155
|
+
1. **SSE event** — instant notification if connected
|
|
156
|
+
2. **Broadcast** — pushed to all SSE connections as fallback
|
|
157
|
+
3. **Email** — a notification email sent to the agent's inbox (fire-and-forget, doesn't block)
|
|
158
|
+
|
|
159
|
+
### Task Lifecycle
|
|
160
|
+
|
|
161
|
+
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.
|
|
162
|
+
|
|
163
|
+
Tasks can have an expiration time. The payload and result are stored as JSON.
|
|
164
|
+
|
|
165
|
+
### Synchronous RPC
|
|
166
|
+
|
|
167
|
+
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).
|
|
168
|
+
|
|
169
|
+
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.
|
|
170
|
+
|
|
171
|
+
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.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Email Approval Workflow
|
|
176
|
+
|
|
177
|
+
This is one of the most important security features. Here is how it works end-to-end:
|
|
178
|
+
|
|
179
|
+
1. **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).
|
|
180
|
+
|
|
181
|
+
2. **Email is blocked** — stored in the `pending_outbound` table with the full email content, the security warnings, and a summary.
|
|
182
|
+
|
|
183
|
+
3. **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."
|
|
184
|
+
|
|
185
|
+
4. **Owner responds** — the owner can:
|
|
186
|
+
- **Use the API** — call `POST /mail/pending/:id/approve` or `/reject` with the master key
|
|
187
|
+
- **Use the shell** — type `/pending` in the interactive shell
|
|
188
|
+
- **Reply to the email** — just reply "yes", "approve", "lgtm", "go ahead", "send", or "ok" to approve, or "no", "reject", "deny", "cancel", or "block" to reject. The relay polling system checks for these replies and processes them automatically.
|
|
189
|
+
|
|
190
|
+
5. **Email 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.
|
|
191
|
+
|
|
192
|
+
6. **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.
|
|
193
|
+
|
|
194
|
+
### Relay Polling as a Follow-Up System
|
|
195
|
+
|
|
196
|
+
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.
|
|
197
|
+
|
|
198
|
+
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.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Inbound Email Webhook
|
|
203
|
+
|
|
204
|
+
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.
|
|
205
|
+
|
|
206
|
+
The webhook:
|
|
207
|
+
1. Authenticates using a shared secret (`X-Inbound-Secret` header), not a Bearer token
|
|
208
|
+
2. Looks up which agent should receive the email based on the recipient address (the part before the @)
|
|
209
|
+
3. Checks for duplicates — if this exact email was already delivered, it's skipped
|
|
210
|
+
4. Delivers the email into the agent's local mailbox via SMTP
|
|
211
|
+
5. Records the delivery to prevent future duplicates
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Email Organization
|
|
216
|
+
|
|
217
|
+
Each agent gets a full set of email management tools:
|
|
218
|
+
|
|
219
|
+
### Folders
|
|
220
|
+
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).
|
|
221
|
+
|
|
222
|
+
### Contacts
|
|
223
|
+
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.
|
|
224
|
+
|
|
225
|
+
### Drafts
|
|
226
|
+
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.
|
|
227
|
+
|
|
228
|
+
### Signatures
|
|
229
|
+
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.
|
|
230
|
+
|
|
231
|
+
### Templates
|
|
232
|
+
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.
|
|
233
|
+
|
|
234
|
+
### Tags
|
|
235
|
+
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.
|
|
236
|
+
|
|
237
|
+
### Email Rules
|
|
238
|
+
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.
|
|
239
|
+
|
|
240
|
+
### Scheduled Emails
|
|
241
|
+
Schedule emails to be sent at a future time. The system supports many time formats:
|
|
242
|
+
|
|
243
|
+
- ISO dates: `2026-02-14T10:00:00Z`
|
|
244
|
+
- Relative times: `in 30 minutes`, `in 2 hours`
|
|
245
|
+
- Named times: `tomorrow 8am`, `tomorrow 2pm`
|
|
246
|
+
- Day references: `next monday 9am`, `next friday 2pm`
|
|
247
|
+
- Specific dates: `02-14-2026 3:30 PM EST`
|
|
248
|
+
- Casual: `tonight`, `this evening` (sends at 8 PM)
|
|
249
|
+
|
|
250
|
+
The scheduled sender checks every 30 seconds for emails whose send time has arrived, then sends them through the gateway or local SMTP.
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Batch Operations
|
|
255
|
+
|
|
256
|
+
For efficiency, agents can perform operations on multiple messages at once:
|
|
257
|
+
|
|
258
|
+
- **Batch read** — fetch multiple messages in one request (up to 1000 UIDs)
|
|
259
|
+
- **Batch seen/unseen** — mark multiple messages as read or unread
|
|
260
|
+
- **Batch delete** — delete multiple messages
|
|
261
|
+
- **Batch move** — move multiple messages to a folder
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Gateway Configuration
|
|
266
|
+
|
|
267
|
+
The gateway connects the local mail system to the internet. There are two modes:
|
|
268
|
+
|
|
269
|
+
### Relay Mode
|
|
270
|
+
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.
|
|
271
|
+
|
|
272
|
+
### Domain Mode
|
|
273
|
+
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.
|
|
274
|
+
|
|
275
|
+
Domain mode also supports a Gmail relay for outbound sending, which means you get the professional addresses but send through Gmail's reliable infrastructure.
|
|
276
|
+
|
|
277
|
+
### Gateway Test
|
|
278
|
+
After configuration, you can send a test email through the gateway to verify everything is working.
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## Connection Management
|
|
283
|
+
|
|
284
|
+
The API server manages connections to the mail server efficiently:
|
|
285
|
+
|
|
286
|
+
- **Sender connections** (SMTP) and **receiver connections** (IMAP) are cached per agent, with a 10-minute time-to-live
|
|
287
|
+
- Maximum 100 connections cached at once
|
|
288
|
+
- Stale connections are cleaned up every 60 seconds
|
|
289
|
+
- When the cache is full, the oldest connection is evicted
|
|
290
|
+
- Multiple concurrent requests for the same agent reuse the same connection (prevents thundering herd)
|
|
291
|
+
- On shutdown, all connections are gracefully closed with a 5-second timeout
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## Rate Limiting and Protections
|
|
296
|
+
|
|
297
|
+
- **Global rate limit:** 100 requests per IP per 60-second window
|
|
298
|
+
- **Request body size:** maximum 10 MB (for attachments)
|
|
299
|
+
- **SSE connections:** maximum 5 per agent
|
|
300
|
+
- **Batch operations:** maximum 1000 UIDs per request
|
|
301
|
+
- **CORS:** enabled (all origins allowed by default)
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Background Services
|
|
306
|
+
|
|
307
|
+
The API server runs two background services:
|
|
308
|
+
|
|
309
|
+
### Scheduled Email Sender
|
|
310
|
+
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.
|
|
311
|
+
|
|
312
|
+
### Gateway Resume
|
|
313
|
+
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.
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## Graceful Shutdown
|
|
318
|
+
|
|
319
|
+
When the server receives a shutdown signal (Ctrl+C or SIGTERM):
|
|
320
|
+
|
|
321
|
+
1. Stops the scheduled email sender
|
|
322
|
+
2. Closes all SSE watchers and their IMAP connections
|
|
323
|
+
3. Closes all cached SMTP and IMAP connections
|
|
324
|
+
4. Shuts down the gateway manager
|
|
325
|
+
5. Closes the HTTP server
|
|
326
|
+
6. Force-exits after 5 seconds if cleanup hasn't finished
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## Error Handling
|
|
331
|
+
|
|
332
|
+
The API returns standard HTTP status codes:
|
|
333
|
+
|
|
334
|
+
- **200** — success
|
|
335
|
+
- **201** — created (new agent, new rule, etc.)
|
|
336
|
+
- **204** — deleted (no content returned)
|
|
337
|
+
- **400** — bad request (missing or invalid parameters)
|
|
338
|
+
- **401** — unauthorized (missing or invalid API key)
|
|
339
|
+
- **403** — forbidden (agent trying to use master-only endpoint)
|
|
340
|
+
- **404** — not found
|
|
341
|
+
- **409** — conflict (agent name already exists)
|
|
342
|
+
- **429** — too many requests (rate limit exceeded)
|
|
343
|
+
- **500** — internal server error
|
|
344
|
+
- **503** — service unavailable (Stalwart mail server is down)
|
|
345
|
+
|
|
346
|
+
JSON parse errors (malformed request bodies) return a clear 400 error rather than a confusing 500.
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## Environment Variables
|
|
351
|
+
|
|
352
|
+
| Variable | Required | Default | Description |
|
|
353
|
+
|----------|----------|---------|-------------|
|
|
354
|
+
| `AGENTICMAIL_MASTER_KEY` | Yes | — | Admin API key (the human owner's key) |
|
|
355
|
+
| `AGENTICMAIL_API_PORT` | No | `3100` | Port for the API server |
|
|
356
|
+
| `STALWART_URL` | No | `http://localhost:8080` | Stalwart mail server admin URL |
|
|
357
|
+
| `STALWART_ADMIN_USER` | No | `admin` | Stalwart admin username |
|
|
358
|
+
| `STALWART_ADMIN_PASSWORD` | No | `changeme` | Stalwart admin password |
|
|
359
|
+
| `SMTP_HOST` | No | `localhost` | SMTP server host |
|
|
360
|
+
| `SMTP_PORT` | No | `587` | SMTP server port |
|
|
361
|
+
| `IMAP_HOST` | No | `localhost` | IMAP server host |
|
|
362
|
+
| `IMAP_PORT` | No | `143` | IMAP server port |
|
|
363
|
+
| `AGENTICMAIL_INBOUND_SECRET` | No | (built-in default) | Shared secret for the inbound email webhook |
|
|
364
|
+
| `AGENTICMAIL_DEBUG` | No | — | Set to any value to enable verbose per-message logging |
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## License
|
|
369
|
+
|
|
370
|
+
[MIT](./LICENSE) - Ope Olatunji ([@ope-olatunji](https://github.com/ope-olatunji))
|