For agents

Email for AI agents.

An agent that only has SMTP can send. It cannot read the reply, list the inbox, or wake up when mail arrives. Kontacts is a project mailbox with a key — send, list, webhooks, and MCP. Not IMAP, and not a published SDK: curl, fetch, or the hosted MCP URL.

Machine-readable how it works: /llm.txt. Same body at /llms.txt.

Agents need a mailbox, not just a send endpoint

Transactional APIs are built for password resets. An agent that handles support, inbound leads, or a booking follow-up needs the other half: a real address that receives, a thread it can read, and an event when something lands. Kontacts is that mailbox, owned by the project — the same inbox the team already uses.

Point a domain at Kontacts and the project gets a real address. Mail to any address at the domain lands in the inbox. Your agent authenticates with a Bearer key you mint yourself. There is no session-cookie path and no dashboard scraping.

What ships today

Four surfaces, one key. Mint it under Settings → API keys (/dashboard/settings/api-keys). The plaintext is shown once. Put it on Authorization: Bearer …. The prefix is gm_live_.

  • REST send/api/v1/send with JSON { to, subject, text, html? }. There is no from — the project identity decides. Success is 201. How to call it.
  • REST list/api/v1/emails lists mail the key can see. Optional ?project_id= for a key that reaches more than one project. This is a list, not a single-message GET — read one message with MCP get_email.
  • Signed webhooksRegister an HTTPS URL under Settings → Webhooks (/dashboard/settings/webhooks). Events: email.received, email.sent, email.bounced, form.submitted, booking.created, booking.cancelled, webhook.test. Verify X-Kontacts-Signature. Mail payloads are envelope metadata — the inbox holds the body. Webhook contract.
  • Hosted MCPThe same key authenticates /api/v1/mcp at https://kontacts.dev/api/v1/mcp. Read tools: list_projects, key_info, list_emails, get_email, list_domains, list_bookings, list_meeting_types, list_contacts, get_board, list_cards, list_comments, list_audiences, list_subscribers, list_issues, get_issue, get_issue_stats, preview_issue, list_forms, get_form, list_submissions, get_submission. Write tools: send_email, reply_email, add_domain, verify_domain, create_meeting_type, set_meeting_type_active, set_availability, create_contact, update_contact, delete_contact, publish_kanban, set_kanban_public_editing, update_board, add_column, rename_column, move_column, delete_column, create_card, update_card, move_card, delete_card, delete_comment, create_audience, set_audience_enabled, create_draft, update_draft, send_issue, create_form, update_form, set_form_fields, set_form_enabled, set_form_origins, archive_form, duplicate_form, release_submission. Rate limit is 60 requests per minute per key. Cursor and Claude setup.

Call it with curl — there is no SDK to install

We have not published an npm package. The contract is HTTP. Copy these from the same modules /help already renders.

curl -X POST https://kontacts.dev/api/v1/send \
  -H "Authorization: Bearer gm_live_…" \
  -H "Content-Type: application/json" \
  -d '{"to":"teammate@example.com","subject":"Hello","text":"Sent from the API"}'
curl https://kontacts.dev/api/v1/emails \
  -H "Authorization: Bearer gm_live_…"

Cursor takes a remote MCP URL. Put the key in a header, not in a prompt:

{
  "mcpServers": {
    "kontacts": {
      "url": "https://kontacts.dev/api/v1/mcp",
      "headers": {
        "Authorization": "Bearer gm_live_…"
      }
    }
  }
}
claude mcp add --transport http kontacts https://kontacts.dev/api/v1/mcp \
  --header "Authorization: Bearer gm_live_…"

A webhook delivery looks like this — no API keys, no signing secrets, no message body:

{
  "id": "delivery-uuid",
  "type": "email.received",
  "created_at": "2026-09-03T20:00:00.000Z",
  "data": {
    "email_id": "email-uuid",
    "provider_id": "resend-email-id",
    "from": "ada@example.com",
    "to": ["inbox@acme.com"],
    "subject": "Hello",
    "direction": "inbound"
  }
}

Kontacts also has a documentation site, at docs.kontacts.dev.

What a Kontacts mailbox is not

It is not a mail client. There is no IMAP, so you cannot point Thunderbird or Apple Mail at it — same limit as the project inbox. Agents use REST and MCP, not a desktop client.

Outbound send and MCP send_email / reply_email draw on the same organisation pool, capped on Free at 10 sends per UTC day. Receiving is unmetered. A reply in an existing thread is MCP reply_email (needs confirm: true) or the inbox composer — not /api/v1/send.

Receiving needs a domain you can add DNS records to. A free address on kontacts.dev is planned, not built.

The inbox still belongs to the project

The agent is another client of the same mailbox the team already sees. GitHub issue routing is optional and off by default. When you turn it on, mail to the addresses on your list opens a GitHub issue. Mail that fails sender authentication is held in the inbox and marked quarantined instead. The optional catch-all counts every address as declared for that gate — it does not decide whether mail is received.

Keys live at Settings → API keys. Webhooks live next to them. The suite — inbox, booking page, forms, kanban, newsletters — stays the product. Agents are a lane on that mailbox, not a replacement for it.

Give the agent a key. Give the project the inbox.