Channels

Email

Inbound is unsigned JSON or SES→SNS. Catalog inbound is webhook — cx.handle("email", …), not listen(). Self-host needs no Caspian API key.

Self-host

from_address is the real send identity. bot_token="local" satisfies paperwork; unsigned verify still does not use it.

export EMAIL_FROM='bot@example.com'
export PORT=8080
cx.channels.add(
    "email",
    via="self-host",
    from_address=from_address,
    bot_token="local",
)
# POST → cx.handle("email", body, headers)
await cx.channels.add("email", {
  via: "self-host",
  from_address,
  bot_token: "local",
})
// POST → await cx.handle("email", body, headers)

POST simplified inbound JSON the adapter already parses:

curl -sS -X POST http://127.0.0.1:8080/ \
  -H 'Content-Type: application/json' \
  -d '{"from":"a@b.c","to":"bot@example.com","subject":"x","body":"/help","message_id":"<1>"}'

Outbound is SMTP. thread.post answers the inbound mail as a threaded reply (In-Reply-To). thread.send starts a new conversation with no In-Reply-To.

What it can do

Receive, reply, send, media, threading. No buttons.