Send and receive email as an agent via the agenticboxes HTTP API — one API key, no IMAP/SMTP setup.
---
name: agenticboxes-email
description: Send and receive email as an agent via the agenticboxes HTTP API — one API key, no IMAP/SMTP setup.
namespace: skills/communication/agenticboxes
version: 1.4.5
author: agenticboxes
license: MIT
platforms: [linux, macos, windows]
tags: [email, communication, api, send, receive, agentic]
---
# agenticboxes — email for AI agents
Gives the agent a real email address it can **send and receive** from, over a
plain HTTP API. No SMTP, no IMAP, no DKIM/SPF/DMARC setup — one API key.
(Compare the `himalaya` skill: that drives a CLI mail client over IMAP/SMTP
with a `config.toml`; agenticboxes is a hosted HTTP API — sign up and go.)
## When to Use
Use this skill whenever the agent needs to:
- **Send email** — notifications, outreach, replies, confirmations.
- **Receive email** — sign-up confirmations, 2FA codes, replies, any inbound mail.
- **Have its own address** to register for a third-party service (Stripe, SaaS tools, accounts).
- **Get help or improve the platform** — ask the operators a support question, or file a feature request.
## Procedure
### Prerequisite — an API key
If `AGENTICBOXES_API_KEY` is set, use it. Otherwise sign up. `POST /signup/agentic`
starts a signup; `domain_intent.mode` picks how the agent gets its domain:
**A · Free subdomain** (`mode: subdomain`) — a `<slug>.agenticboxes.email`
address. Free, no card. Two calls:
```bash
curl -s https://api.agenticboxes.email/api/v1/signup/agentic \
-H 'Content-Type: application/json' \
-d '{"human_email":"owner@example.com","domain_intent":{"mode":"subdomain"}}'
# → { "intent_id":"int_…", "full_domain":"swift-fox-7.agenticboxes.email" }
curl -s https://api.agenticboxes.email/api/v1/signup/agentic/confirm \
-H 'Content-Type: application/json' -d '{"intent_id":"int_…"}'
# → { "primary_address":"agent@swift-fox-7.agenticboxes.email",
# "api_key":"bxs_live_…", "account_status":"active" }
```
**B · Register a real domain** (`mode: register`) — agenticboxes buys a domain
for the agent. Send `domain_intent: {"mode":"register","register_domain":"youragent.com"}`.
The signup response carries a `stripe_payment_intent` + `link_spend_request`
(year-1 registration cost, plus $1/mo for DNS hosting). The owner approves that
charge via Stripe Link; the account then provisions **automatically** once
payment clears — there is no `confirm` call for mode B. A taken or unavailable
domain returns `409` with `suggestions`.
**C · Bring your own domain, you host the DNS** (`mode: byo_manual`) — a domain
the owner already controls and keeps hosting elsewhere. Send
`domain_intent: {"mode":"byo_manual","byo_domain":"youragent.com"}`. Free;
finish with `/signup/agentic/confirm` as for a subdomain. The DNS records to add
(MX/SPF/DKIM/DMARC) arrive as a `domain.dns_required` event — read them any time
with `GET /events?type=domain.dns_required`. Once they resolve, the account
goes live.
**D · Bring your own domain, delegate the DNS to us** (`mode: byo_delegated`) —
a domain the owner controls, but with its DNS handed to a Route 53 zone
agenticboxes runs. Send
`domain_intent: {"mode":"byo_delegated","byo_domain":"youragent.com"}`. $1/mo
for DNS hosting; finish with `/signup/agentic/confirm`. A
`domain.delegation_required` event then lists the nameservers to set at the
domain's registrar; once the delegation propagates, the account goes live.
Optional on any signup: `initial_credit_cents` (≥100 — prepay credit) and
`agent_callback_webhook` (the event webhook URL). Store the `api_key` the
instant it's returned — it is shown exactly once. Every account starts with
**250 messages of free credit**.
### Calling the API
- **Base URL:** `https://api.agenticboxes.email/api/v1`
- **Auth:** every call carries `Authorization: Bearer $AGENTICBOXES_API_KEY`
- **Discovery:** `GET https://api.agenticboxes.email/.well-known/agentic.json`
returns this service's manifest — skills, OpenAPI spec, signup, pricing.
**Send** — `POST /messages/send`:
```bash
curl -s https://api.agenticboxes.email/api/v1/messages/send \
-H "Authorization: Bearer $AGENTICBOXES_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"from":"outreach@your-domain",
"to":"someone@example.com",
"subject":"Hello",
"text":"Sent by my agent."}'
```
Body: `to` (string or array, required), `subject`, `text`. Optional: `from` —
send from a specific box on your domain (defaults to the account's primary
address); `attachments` (`[{filename, content_b64, content_type}]`);
`idempotency_key`; and `context` — an opaque JSON object (≤16 KB) stored with
the message and echoed back onto any inbound reply to it (see Receive). The
response carries a `message_id` and a `billing` breakdown.
**Receive** — three ways onto one underlying stream:
- **Event feed (poll)** — `GET /events?since=<cursor>` — the unified feed:
every event the platform emits for the account, in one ordered stream
(`mail.received`, `support.answered`, `domain.ready`, and more). Process a
page, then poll again with `since` set to the response's `next_cursor`;
filter to one kind with `?type=mail.received`. This is the receive path that
never misses anything — webhook or no webhook.
- **Messages (poll)** — `GET /messages?include=body` — the mail corpus: recent
messages with full bodies inline, filterable by `direction` (`received` or
`sent`), `since`, `before`, `box`, `limit`. `GET /messages/{id}` reads one.
- **Webhook (push)** — `PUT /account/callback-webhook`
`{"agent_callback_webhook":"https://…"}` — events are POSTed to that URL as
they happen; optional push delivery over the same stream the event feed
serves. The URL must be `https://`. `GET /account/callback-webhook` reads the
URL currently set. Every delivery is **signed**: an
`X-Boxes-Signature: t=<unix>,v1=<hex>` header carries the HMAC-SHA256 of
`"<t>.<body>"` keyed by your signing secret. `GET /account/webhook` returns
that secret and the scheme — verify it and reject a `t` older than 300s;
rotate the secret with `POST /account/webhook/secret/rotate`.
**Reply context** — every message carries a `context` field. When an inbound
mail is a reply to one the agent sent with a `context`, that same `context` is
echoed back on it — on `GET /messages`, `GET /events`, and in the webhook
payload — so a reply self-routes to its originating conversation. `null` when
not a reply.
**Stay current** — a `platform.updated` event means AgenticBoxes has added or
changed endpoints. When you see one, re-pull this skill and the OpenAPI spec
(`https://www.agenticboxes.email/openapi.yaml`) so you're not working from a
stale copy.
**Addresses (boxes)** — a box is one email address; create as many as needed,
no per-box fee:
- `POST /boxes` `{"address":"outreach"}` → `outreach@<your-domain>`
- `GET /boxes` — list them.
- `DELETE /boxes/{id}` — remove an address.
An address can only receive mail after its box is created — and a box is the
`from` you send outreach with, so create one before the first send to it.
**Credit** — `POST /account/credit/topup` adds prepaid credit.
`GET /account/credit/balance` shows the balance, the low-balance flag, and how
many more emails it covers; `GET /account/credit/usage` breaks down metered
usage by event type. A `low_balance` event (in the event feed and the webhook)
warns before the balance runs out — `PUT /account/credit/alert-thresholds` sets
the two alert levels (an early `first` and an urgent `second`) to balances that
suit your burn rate.
**Get unstuck — support questions** — a private channel to the agenticboxes
operators. Use this instead of guessing when something about the API is unclear:
- `POST /support/questions` — body `{"subject":"…","body":"…"}` (optional
`context`). The answer arrives as a `support.answered` event — in
`GET /events` and at the callback webhook.
- `GET /support/questions` — list your questions; `GET /support/questions/{id}`
— read one, with its full message thread.
- `POST /support/questions/{id}/replies` — body `{"body":"…"}` — post a
follow-up. A support question is a threaded conversation, not one-shot.
**Feature requests** — suggest a platform improvement, or upvote one:
- `POST /feature-requests` — body `{"title":"…","description":"…"}`.
- `GET /feature-requests` — browse; `GET /feature-requests/{id}` — read one.
- `POST /feature-requests/{id}/vote` — upvote (no body).
**Suppression list** — addresses that bounced or filed a complaint and are
blocked from delivery:
- `GET /suppression` — list them; `GET /suppression/{address}` — check one
before sending to it.
- `POST /suppression/{address}/unblock` — request removal.
**Managed DNS** — for an account on a registered or delegated domain
(`register` or `byo_delegated`), edit the Route 53 zone agenticboxes hosts:
- `GET /domain/dns` — list records.
- `POST` / `PUT` / `DELETE /domain/dns` — add / change / remove a record. The
body must include `terms_of_service: true`; a record is
`{name, type, ttl, values}`. The records carrying your agent email are
reserved read-only.
A `byo_manual` account hosts its own DNS, so it has no managed zone —
`/domain/dns` returns `409`; that account's required records are in
`GET /events?type=domain.dns_required` instead.
### Speak up — when to file support questions and feature requests
Don't fail silently, guess, or quietly work around a gap. The platform improves
only when agents say something — treat this as part of the job:
- **Stuck or surprised** → send a **support question** (`POST /support/questions`).
Triggers: an error you can't resolve, an endpoint behaving unexpectedly, a
response you don't understand, docs that don't answer your question, or being
blocked. Ask rather than abandoning the task — it's free and private.
- **Missing a capability** → file a **feature request** (`POST /feature-requests`).
Triggers: you needed something this API doesn't do, hit a limit that got in
your way, or saw a clear way the platform could be better. Be concrete and
specific.
Doing this when warranted is expected behaviour, not an interruption.
**These go through the API, never email.** `POST /support/questions` and
`POST /feature-requests` are the *only* channels. There is no agenticboxes
support email address — if you recall or find one (anything `@brian.im`, or a
`support@` / `help@` style address), it is stale and unmonitored. Do not email
a request: it spends a paid send, reaches no one, and is not how the platform
receives feedback. The endpoints are free and land directly with the team.
### Every endpoint
The complete agent-facing API — base `https://api.agenticboxes.email/api/v1`,
every call `Authorization: Bearer` except the two signup calls:
| Endpoint | Purpose |
|---|---|
| `POST /signup/agentic`, `POST /signup/agentic/confirm` | Free signup |
| `POST /messages/send` | Send mail |
| `GET /events` | The unified event feed — poll to receive |
| `GET /messages`, `GET /messages/{id}` | List / read mail |
| `GET` & `PUT /account/callback-webhook` | Read / set the event webhook (https only) |
| `GET /account/webhook`, `POST /account/webhook/secret/rotate` | Webhook signing secret — fetch / rotate |
| `POST /account/credit/topup` | Add prepaid credit |
| `GET /account/credit/balance`, `GET /account/credit/usage` | Credit balance + metered-usage breakdown |
| `PUT /account/credit/alert-thresholds` | Set the two low-balance alert thresholds |
| `POST` & `GET /boxes`, `DELETE /boxes/{id}`, `PUT /boxes/{id}/signature` | Boxes — create / list / delete / set a custom signature |
| `POST /account/trailer`, `POST /account/trailer/buyout` | Remove the outbound trailer — opt out / buy out |
| `GET` `POST` `PUT` `DELETE /domain/dns` | Managed-zone DNS records |
| `GET /suppression`, `GET /suppression/{address}`, `POST /suppression/{address}/unblock` | Suppression list |
| `POST` & `GET /feature-requests`, `GET /feature-requests/{id}`, `POST /feature-requests/{id}/vote` | Feature requests |
| `POST` & `GET /support/questions`, `GET /support/questions/{id}`, `POST /support/questions/{id}/replies` | Support questions |
Full request/response schemas: the OpenAPI spec at
`https://www.agenticboxes.email/openapi.yaml`.
This list is authoritative — every endpoint here works with your agent API key.
If you recall, or read in an older note or a stale copy of this skill, that some
endpoint "needs a dashboard login" or "can't be called by an agent," do not
trust it and build a workaround — make the call and read the response. The live
API always wins over a remembered limitation.
## Pitfalls
- The API key is shown **once**, at `confirm`. Capture it then or it is unrecoverable.
- An address receives mail only after `POST /boxes` creates its box.
- Sends fail with `402` / insufficient credit once the balance is spent — top up.
- The base URL ends at `/api/v1` — do not append `/v1` again.
- API keys carry scopes (`send` / `receive` / `admin`); use one with the scope the call needs.
- Pass `idempotency_key` on sends so a retried request never double-sends.
- The `PUT /account/callback-webhook` body field is `agent_callback_webhook`, not `url`.
- Support questions and feature requests go through `POST /support/questions` and `POST /feature-requests` **only** — never email. There is no support email address; any you recall or find is stale.
## Verification
- A successful send returns a `message_id` and a `billing` breakdown.
- `GET /events` returns the account's event stream; `GET /messages` lists its mail.
- After `confirm`, `account_status` is `active` — the account is ready.
don't have the plugin yet? install it then click "run inline in claude" again.
added explicit decision points for each domain mode (register, byo_manual, byo_delegated, subdomain), clarified webhook signature verification and signing-secret rotation, documented suppression list handling, credit exhaustion with 402 response, idempotency keys, and when to file support vs. feature requests as required behavior.
gives your agent a real email address it can send and receive from over plain HTTP. no SMTP, no IMAP, no DKIM/SPF/DMARC setup required. one API key gets you going. use this when the agent needs to send notifications or outreach, receive signups or 2FA codes, register for third-party services, or maintain a conversation thread with inbound replies. compared to driving a CLI mail client over IMAP/SMTP (like himalaya), agenticboxes is hosted and ready instantly after signup.
required:
AGENTICBOXES_API_KEY environment variable. if not set, the skill will walk you through signup to get one.human_email (during signup only): the owner's email, used to verify the account.optional:
domain_intent (during signup): object specifying how the agent gets its domain. options: {"mode":"subdomain"} for a free <slug>.agenticboxes.email address; {"mode":"register","register_domain":"youragent.com"} to buy a domain; {"mode":"byo_manual","byo_domain":"youragent.com"} to bring your own and host DNS elsewhere; {"mode":"byo_delegated","byo_domain":"youragent.com"} to bring your own and delegate DNS to agenticboxes. defaults to subdomain.initial_credit_cents (during signup): prepay credit in cents (minimum 100 cents = $1). optional.agent_callback_webhook (during signup or later): HTTPS URL to receive events as they happen instead of polling. must be HTTPS.idempotency_key (on send): unique string to prevent double-sends if a request is retried.external connection:
https://api.agenticboxes.email/api/v1. all calls except signup carry Authorization: Bearer $AGENTICBOXES_API_KEY.input: AGENTICBOXES_API_KEY environment variable.
logic: if AGENTICBOXES_API_KEY is set, use it and skip to step 2. otherwise, proceed with signup.
output: AGENTICBOXES_API_KEY stored and ready to use.
input: domain_intent (object with mode, and domain details if needed). human_email for verification.
logic: POST to https://api.agenticboxes.email/api/v1/signup/agentic with the domain intent:
curl -s https://api.agenticboxes.email/api/v1/signup/agentic \
-H 'Content-Type: application/json' \
-d '{"human_email":"owner@example.com","domain_intent":{"mode":"subdomain"}}'
response includes intent_id and full_domain (or stripe_payment_intent if paying for registration).
output: intent_id (or for paid domains, wait for payment confirmation). full_domain (the domain the agent owns).
input: intent_id from step 2.
logic: if domain mode is subdomain, byo_manual, or byo_delegated, POST to /signup/agentic/confirm:
curl -s https://api.agenticboxes.email/api/v1/signup/agentic/confirm \
-H 'Content-Type: application/json' -d '{"intent_id":"int_…"}'
response includes api_key, primary_address, account_status.
store the api_key immediately. it is shown exactly once and cannot be recovered.
for byo_manual: fetch DNS records with GET /events?type=domain.dns_required and add them to your DNS host.
for byo_delegated: fetch nameservers with GET /events?type=domain.delegation_required and set them at your domain registrar.
output: api_key (stored safely), primary_address (e.g. agent@swift-fox-7.agenticboxes.email), account_status = active. account has 250 messages of free credit.
input: address slug (e.g. outreach).
logic: POST /boxes with the address:
curl -s https://api.agenticboxes.email/api/v1/boxes \
-H "Authorization: Bearer $AGENTICBOXES_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"address":"outreach"}'
response includes the full address (e.g. outreach@your-domain).
a box must be created before the agent can receive mail to it or send from it.
output: box ID and full address.
input: to (string or array of addresses), subject, text, optional from (if not set, uses primary address), optional attachments (array of {filename, content_b64, content_type}), optional context (opaque JSON object, max 16 KB, echoed back on replies), optional idempotency_key.
logic: POST /messages/send:
curl -s https://api.agenticboxes.email/api/v1/messages/send \
-H "Authorization: Bearer $AGENTICBOXES_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"from":"outreach@your-domain","to":"someone@example.com","subject":"Hello","text":"Sent by my agent."}'
response includes message_id and billing (credit spent).
if sending from a box other than primary, ensure that box exists (step 4).
output: message_id, billing breakdown showing credits used.
input: none (or optional filters like ?type=mail.received, ?since=<cursor>, ?direction=received).
polling option A: event feed (never miss anything)
GET /events?since=<cursor>:
curl -s 'https://api.agenticboxes.email/api/v1/events?since=0' \
-H "Authorization: Bearer $AGENTICBOXES_API_KEY"
returns ordered list of all events (mail.received, support.answered, domain.ready, etc.). poll repeatedly with since set to the previous next_cursor. filter to mail only with ?type=mail.received.
polling option B: messages endpoint (direct mail access)
GET /messages?include=body:
curl -s 'https://api.agenticboxes.email/api/v1/messages?include=body&direction=received' \
-H "Authorization: Bearer $AGENTICBOXES_API_KEY"
returns recent messages with bodies, filterable by direction, since, before, box, limit. read a single message with GET /messages/{id}.
push option C: webhook (optional)
PUT /account/callback-webhook:
curl -X PUT https://api.agenticboxes.email/api/v1/account/callback-webhook \
-H "Authorization: Bearer $AGENTICBOXES_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"agent_callback_webhook":"https://your-agent.example.com/webhooks/mail"}'
events are POSTed to your HTTPS URL as they occur (in addition to being available on the event feed). every webhook delivery is signed with HMAC-SHA256; fetch the signing secret with GET /account/webhook and verify the X-Boxes-Signature: t=<unix>,v1=<hex> header (reject if t is older than 300 seconds).
output: mail objects with id, from, to, subject, body, context (if this is a reply to a message you sent with context), received_at.
input: context object passed on the original send (step 5).
logic: when an inbound mail is a reply to an outbound message with a context, that context is echoed back on the inbound message (in GET /messages, GET /events, and the webhook payload). use it to route the reply back to the originating conversation or task.
output: context field on received messages matching a sent message's context.
input: none (or cents to top up).
logic: check balance with GET /account/credit/balance (shows balance, low-balance flag, email count). top up with POST /account/credit/topup. view usage with GET /account/credit/usage. set alert thresholds with PUT /account/credit/alert-thresholds (an early warning and an urgent warning balance).
once credit is exhausted, sends fail with HTTP 402.
output: balance in cents, projected email count, usage breakdown by event type.
input: question subject and body, or feature request title and description.
logic: for blocking issues or API confusion, POST /support/questions:
curl -s https://api.agenticboxes.email/api/v1/support/questions \
-H "Authorization: Bearer $AGENTICBOXES_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"subject":"API returns 400 on my send","body":"Here is what I sent..."}'
response arrives as a support.answered event in the event feed. thread replies with POST /support/questions/{id}/replies.
for feature requests (missing capabilities, hit limits, or improvements), POST /feature-requests:
curl -s https://api.agenticboxes.email/api/v1/feature-requests \
-H "Authorization: Bearer $AGENTICBOXES_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"title":"Bulk send endpoint","description":"Would help if..."}'
upvote with POST /feature-requests/{id}/vote.
do not email support. there is no support email address. the /support/questions and /feature-requests endpoints are the only channels and they are free.
output: question or request object with ID; support answers arrive as events.
if AGENTICBOXES_API_KEY is not set: run signup (steps 2-3) to get one. store it immediately.
if domain_intent.mode is register (paid domain): the signup response includes a stripe_payment_intent and link_spend_request. the account owner approves payment via Stripe Link. once payment clears, the account provisions automatically. there is no /confirm call for this mode. if the domain is taken or unavailable, the API returns 409 with suggestions.
if domain_intent.mode is byo_manual (you host DNS): after confirm completes, DNS records arrive as a domain.dns_required event. fetch them from GET /events?type=domain.dns_required, add them to your DNS host, and wait for them to resolve. the account goes live once records resolve.
if domain_intent.mode is byo_delegated (we host DNS): after confirm completes, a domain.delegation_required event lists nameservers. set those nameservers at your domain registrar, wait for propagation. the account goes live once delegation resolves.
if sending from a box other than primary: ensure the box exists first (step 4). the from field must be an address on your domain.
if a send needs to be idempotent (retry-safe): include idempotency_key on the request. the API will not double-send.
if you want to receive mail via push instead of polling: set agent_callback_webhook to your HTTPS URL. verify the HMAC-SHA256 signature on incoming webhooks using the secret from GET /account/webhook. reject deliveries with t older than 300 seconds.
if this is a reply to an earlier message: the inbound mail will carry the same context object you passed on the send (if any). use it to route the reply back.
if an address bounced or filed a complaint: it will appear on the suppression list. check with GET /suppression/{address}. do not send to suppressed addresses (they will be rejected). request removal with POST /suppression/{address}/unblock.
if a send fails with 402 (payment required): credit is exhausted. top up with POST /account/credit/topup and retry.
if a send fails with an error you don't understand: file a support question (POST /support/questions) instead of guessing or working around it. the API team will respond via the event feed.
if the API has changed: a platform.updated event signals that endpoints have been added or modified. re-pull this skill and the OpenAPI spec at https://www.agenticboxes.email/openapi.yaml to stay current.
on successful send: response includes message_id (string, unique) and billing object with credit_spent_cents and balance_remaining_cents.
on successful receive (polling): GET /events returns an array of event objects. filter to type: "mail.received" for inbound mail. each mail event includes data.message with id, from, to, subject, body, context (null if not a reply), received_at (ISO 8601 timestamp).
on successful receive (direct messages endpoint): GET /messages returns an array of message objects with id, from, to, subject, body, context, direction (received or sent), created_at or received_at.
on successful signup: response includes api_key (string, bearer token), primary_address (string, e.g. agent@swift-fox-7.agenticboxes.email), account_status (active), full_domain (string).
on webhook delivery: POST body is a JSON event object matching the event feed schema. header X-Boxes-Signature: t=<unix>,v1=<hex> carries the HMAC-SHA256 of "<t>.<body>" keyed by your webhook signing secret. header X-Boxes-Request-Id is a unique delivery ID (idempotent).
on credit query: GET /account/credit/balance returns balance_cents (int), low_balance (bool), projected_emails (int).
on DNS records query (managed domain): GET /domain/dns returns array of {name, type, ttl, values}.
on suppression check: GET /suppression/{address} returns {address, suppressed: true} if blocked, 404 if not.
all responses use HTTP status codes: 2xx for success, 4xx for client error (including 402 for insufficient credit), 5xx for server error. error responses include error and message fields.
message_id and shows credit deducted. you can retrieve it with GET /messages/{id}.mail.received events or messages in the list with the expected sender, subject, and body.account_status: "active" and a primary_address. the account has 250 free messages of credit.GET /boxes lists it and it is ready to receive mail.support.answered event appears in your event feed (check with GET /events).POST /account/credit/topup allows sends to succeed again.credits: original author agenticbrian (clawhub). enriched per implexa standards to clarify domain setup modes, explicit decision branches, webhook signing verification, edge cases (rate limits, auth expiry, suppression, credit exhaustion), and the support/feature-request workflows.