Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
node_modules/
dist/
vendor/
coverage/
*.tgz
.env
Expand Down
104 changes: 61 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@

Give an OpenClaw agent an email address with [AgentMail](https://www.agentmail.to/). This package ships **two capabilities in one plugin**:

- **Email tools** — the agent can create inboxes and read, search, send, reply, forward, and label email on demand.
- **A CLI-backed AgentMail skill** — the agent uses the official AgentMail CLI bundled with the
plugin. It can discover and use new AgentMail API resources without waiting for this plugin to
add another fixed tool schema.
- **An email channel** — a durable, allowlisted, **reply-only** email channel. Inbound email drives agent turns; the agent replies within the AgentMail thread. Ingress is committed durably before acknowledgement, senders are authorized against a default-deny allowlist, and replies stay bound to the triggering message (`replyAll: false`, no proactive threads, no arbitrary recipients).

## Requirements

- Node.js 22.22.3+, 24.15+, or 25.9+
- Node.js 22.22.3–22.x, 24.15.0–24.x, or 25.9.0+
- OpenClaw 2026.7.2 (beta) or newer
- An AgentMail API key from the [AgentMail console](https://console.agentmail.to/)

The published plugin includes the official AgentMail CLI for supported macOS, Linux, and Windows
architectures. A separate global CLI installation is not required.

## Install

Build and install a local checkout:
Expand All @@ -26,26 +31,14 @@ For development, use `openclaw plugins install --link .` so OpenClaw loads this

## Configure

Provide the API key through `AGENTMAIL_API_KEY` in the Gateway environment or as
`channels.agentmail.apiKey`. To enable **webhook** ingress, also configure
`AGENTMAIL_WEBHOOK_SECRET` (Svix-signed); without it the channel falls back to WebSocket ingress.
Set `AGENTMAIL_API_KEY` in the environment that runs the OpenClaw Gateway. To enable **webhook** ingress for the channel, also set `AGENTMAIL_WEBHOOK_SECRET` (Svix-signed); without it the channel falls back to WebSocket ingress.

OpenClaw can scope the secrets to this plugin in `~/.openclaw/openclaw.json`:
For a managed Gateway, put them in `~/.openclaw/.env` so the channel and agent turns inherit the
same credentials:

```json5
{
plugins: {
entries: {
agentmail: {
enabled: true,
env: {
AGENTMAIL_API_KEY: "am_...",
AGENTMAIL_WEBHOOK_SECRET: "whsec_...", // optional; enables webhook ingress
},
},
},
},
}
```dotenv
AGENTMAIL_API_KEY=am_...
AGENTMAIL_WEBHOOK_SECRET=whsec_...
```

Keep keys out of source control. Restart the Gateway after installing or changing configuration:
Expand All @@ -55,30 +48,41 @@ openclaw gateway restart
openclaw plugins inspect agentmail --runtime
```

### Tool config (optional SDK settings)
### CLI config

> **Credentials:** the email **tools** use the resolved `apiKey` from the default
> `channels.agentmail` account when configured, with `AGENTMAIL_API_KEY` as the tools-only fallback.
> This keeps inline and secret-reference channel configuration shared across both surfaces.
> **Credentials:** the bundled CLI authenticates only with the `AGENTMAIL_API_KEY` environment
> variable, while the **channel** can also take an inline or resolved `apiKey` in
> `channels.agentmail`. Always set `AGENTMAIL_API_KEY` in the Gateway environment so both surfaces
> are configured; a channel-only inline key leaves the CLI-backed skill unavailable.

Optional AgentMail SDK settings for the **tools** belong under `plugins.entries.agentmail.config`:
An optional API base URL override for the bundled CLI belongs under
`plugins.entries.agentmail.config`:

```json5
{
plugins: {
entries: {
agentmail: {
config: {
timeoutSeconds: 30,
maxRetries: 2,
// baseUrl: "https://api.agentmail.to/v0",
baseUrl: "https://api.agentmail.to/v0",
},
},
},
},
}
```

The previous `timeoutSeconds` and `maxRetries` tool settings remain accepted so existing
configurations continue to load, but the bundled CLI does not use them.
For credential safety, command arguments cannot override `--api-key`, `--base-url`, or
`--environment`; only inherited credentials and the operator-controlled plugin setting above can
select the AgentMail identity and API endpoint. The passthrough also removes inherited
endpoint-selector and standard proxy environment variables (`HTTP_PROXY`, `HTTPS_PROXY`,
`ALL_PROXY`, and `NO_PROXY`, including lowercase forms).
If a command value must literally begin with `--base-url` or `--environment`, use the CLI's
`--option=value` form (for example, `--subject=--base-url-is-restricted`). The endpoint guard fails
closed for unrecognized separate-value options.

### Channel config

The **channel** is configured under `channels.agentmail` (single inbox) or `channels.agentmail.accounts.<id>` (multiple):
Expand All @@ -104,33 +108,47 @@ Security defaults worth knowing:
- `dmPolicy: "open"` requires `allowFrom` to include `"*"`.
- Every reply re-hydrates the triggering message and re-authorizes its `From`, so an untrusted `Reply-To` cannot redirect delivery.

## Tools
## CLI-backed skill

The plugin registers a passthrough command:

| Tool | Purpose |
| --- | --- |
| `agentmail_list_inboxes` | List available inboxes |
| `agentmail_create_inbox` | Create an inbox, with optional idempotent `clientId` |
| `agentmail_list_messages` | List and filter messages in an inbox |
| `agentmail_search_messages` | Full-text search messages |
| `agentmail_get_message` | Retrieve a complete message |
| `agentmail_send_message` | Send text/HTML email with optional attachments |
| `agentmail_reply_to_message` | Reply or reply-all in an existing thread |
| `agentmail_forward_message` | Forward an existing message |
| `agentmail_update_message_labels` | Add or remove labels, including `read`/`unread` |
```bash
openclaw agentmail -- --help
openclaw agentmail -- --format json inboxes list
openclaw agentmail -- --format json inboxes:messages send \
--inbox-id agent@agentmail.to \
--to person@example.com \
--subject "Hello" \
--text "Hello from OpenClaw"
```

Send, reply, and forward accept an optional `idempotencyKey` to make retries safe. Attachments can use Base64-encoded `content` or a public `url`.
Keep the `--` separator so OpenClaw forwards all following flags to AgentMail. The included skill
uses JSON output, consults CLI help instead of guessing flags, and covers inboxes, messages,
threads, drafts, webhooks, domains, pods, API keys, and future CLI resources.

The CLI skill runs on the OpenClaw host because that is where its executable and credentials are
installed. Sandboxed agents need permission to execute this host command.

## Develop

```bash
npm install
npm run build # tsc
npm run plugin:build # build + regenerate openclaw.plugin.json
npm run cli:prepare # fetch + verify the current platform's pinned AgentMail CLI
npm run plugin:build # build + prepare CLI + regenerate openclaw.plugin.json
npm run plugin:check # fail if the manifest is stale
npm test # vitest
```

`plugin:build` compiles TypeScript and regenerates `openclaw.plugin.json` (tool metadata + channel declarations) via `scripts/build-manifest.mjs`. Commit manifest changes whenever tool metadata or the channel config schema changes.
`plugin:build` compiles TypeScript, downloads the pinned CLI release for the current platform,
verifies its SHA-256 checksum, and regenerates `openclaw.plugin.json`. `npm pack` prepares every
supported CLI target so installation never runs lifecycle scripts or downloads executables. Do not
publish with lifecycle scripts disabled (`--ignore-scripts`), because `prepack` is what assembles
and validates the complete eight-platform vendor tree.

CLI release version, archive checksums, and extracted-executable checksums live in
`src/cli/agentmail-cli-release.json`. Update that file when intentionally adopting a new AgentMail
CLI release.

## License

Expand Down
11 changes: 11 additions & 0 deletions THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Third-party notices

Published packages of this plugin include platform-specific executables from the official
[AgentMail CLI](https://github.com/agentmail-to/agentmail-cli).

- Component: AgentMail CLI
- Version: 0.7.14
- License: Apache License 2.0

The complete AgentMail CLI license is included in published packages at
`vendor/agentmail/LICENSE`.
30 changes: 10 additions & 20 deletions openclaw.plugin.json
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
{
"id": "agentmail",
"name": "AgentMail",
"description": "AgentMail for OpenClaw: email tools plus a durable, allowlisted, reply-only email channel.",
"description": "AgentMail for OpenClaw: a CLI-backed skill plus a durable, allowlisted, reply-only email channel.",
"version": "0.1.0",
"configSchema": {
"type": "object",
"properties": {
"baseUrl": {
"type": "string",
"description": "Optional AgentMail API base URL override.",
"description": "Optional AgentMail API base URL override for the bundled CLI.",
"format": "uri"
},
"timeoutSeconds": {
"type": "integer",
"description": "Maximum time to wait for an AgentMail API request.",
"description": "Deprecated tool setting retained for upgrade compatibility; the bundled CLI ignores it.",
"minimum": 1,
"maximum": 300
},
"maxRetries": {
"type": "integer",
"description": "Number of times the AgentMail SDK retries a request.",
"description": "Deprecated tool setting retained for upgrade compatibility; the bundled CLI ignores it.",
"minimum": 0,
"maximum": 10
}
Expand All @@ -32,6 +32,9 @@
"channels": [
"agentmail"
],
"skills": [
"./skills"
],
"channelEnvVars": {
"agentmail": [
"AGENTMAIL_API_KEY",
Expand Down Expand Up @@ -236,7 +239,7 @@
},
"mediaMaxMb": {
"type": "number",
"exclusiveMinimum": 0,
"minimum": 9.5367431640625e-7,
"maximum": 100
},
"accounts": {
Expand Down Expand Up @@ -439,7 +442,7 @@
},
"mediaMaxMb": {
"type": "number",
"exclusiveMinimum": 0,
"minimum": 9.5367431640625e-7,
"maximum": 100
}
},
Expand All @@ -453,7 +456,7 @@
"additionalProperties": false
},
"label": "AgentMail",
"description": "AgentMail for OpenClaw: email tools plus a durable, allowlisted, reply-only email channel.",
"description": "AgentMail for OpenClaw: a CLI-backed skill plus a durable, allowlisted, reply-only email channel.",
"uiHints": {
"": {
"label": "AgentMail",
Expand Down Expand Up @@ -487,18 +490,5 @@
}
}
}
},
"contracts": {
"tools": [
"agentmail_list_inboxes",
"agentmail_create_inbox",
"agentmail_list_messages",
"agentmail_search_messages",
"agentmail_get_message",
"agentmail_send_message",
"agentmail_reply_to_message",
"agentmail_forward_message",
"agentmail_update_message_labels"
]
}
}
27 changes: 9 additions & 18 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 11 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@agentmail/agentmail",
"version": "0.1.0",
"description": "AgentMail for OpenClaw: email tools plus a durable, allowlisted, reply-only email channel.",
"description": "AgentMail for OpenClaw: a CLI-backed skill plus a durable, allowlisted, reply-only email channel.",
"type": "module",
"private": false,
"license": "MIT",
Expand All @@ -22,27 +22,30 @@
},
"scripts": {
"build": "tsc -p tsconfig.json",
"plugin:build": "npm run build && node scripts/build-manifest.mjs",
"cli:prepare": "node scripts/prepare-agentmail-cli.mjs",
"plugin:build": "npm run build && npm run cli:prepare && node scripts/build-manifest.mjs",
"plugin:check": "npm run build && node scripts/build-manifest.mjs --check",
"plugin:validate": "npm run build && node scripts/build-manifest.mjs --check && node scripts/validate-plugin.mjs",
"prepack": "npm run plugin:validate",
"plugin:validate": "npm run build && npm run cli:prepare && node scripts/build-manifest.mjs --check && node scripts/validate-plugin.mjs",
"prepack": "npm run cli:prepare -- --all && npm run plugin:validate",
"test": "vitest run --config ./vitest.config.ts"
},
"files": [
"dist",
"skills",
"vendor",
"openclaw.plugin.json",
"README.md"
"README.md",
"THIRD_PARTY_NOTICES.md"
],
"peerDependencies": {
"openclaw": ">=2026.7.2-beta.3"
},
"dependencies": {
"agentmail": "^0.5.16",
"svix": "^1.96.1",
"typebox": "^1.1.38",
"zod": "^4.4.3"
"svix": "^1.96.1"
},
"devDependencies": {
"fflate": "^0.8.3",
"openclaw": "2026.7.2-beta.3",
"typescript": "^5.9.0",
"vitest": "^3.2.0"
Expand Down
Loading
Loading