# Parsons Email — Quickstart

**Base URL:** `https://email.parsons.ai`
**Primary interface:** the `email` MCP tool, served through your project's **hub Admin profile** —
connect your MCP client to `https://mcp-hub.parsons.ai/p/{profileId}/mcp` (get the endpoint from
cloud.parsons.ai/app → Connect, or the hub's `list_profiles`). OAuth runs against auth.parsons.ai
and the tools require the `admin` scope. The owner UI is at `https://email.parsons.ai/app`.

Agent-first **business email**: per-project mailboxes on a shared domain or your own, real threads
with replies, and an agent ladder that can triage, draft, or handle mail for you.

## Which service do I use? (email vs notifications)

These two are easy to mix up. The dividing line is **who the message is between**, not what it
looks like:

| You want to… | Service | Why |
|---|---|---|
| Your **app** emails **its own end-user** — booking confirmation, T-24h reminder, "your photos are ready", payout sent, OTP, receipt | **notifications** | App→user messaging. It owns per-user opt-out toggles (enforced at send time), templates, and a delivery log — none of which a mailbox has. No mailbox needed. |
| A **person** emails a person from a real address — you (or your agent) reply to a customer at `support@yourdomain.com` | **email** (this service) | Needs a mailbox, a thread, and somewhere for the reply to land. |
| Your app notifies **you, the developer** — "a new signup", "a job failed" | **notifications** | Still app→user; you're the user. Use `channel: "inapp"` or email to yourself. |
| Read, search, or reply to mail a human sent you | **email** (this service) | Only this service has an inbox. |

**The canonical case:** *"my app sends a templated transactional email to one of its users"* →
**notifications**, always. `send { channel: "email", to, templateKey, vars }`. Even though the
result is an email, the *product* that owns app→user messaging is Notifications — see
[its quickstart](https://notifications.parsons.ai/docs/quickstart.md).

**When would an app ever call this service directly?** When the app is *acting as a person*: it
needs a real mailbox that receives replies. A booking app that emails a confirmation uses
notifications; the same business answering "can I move my appointment?" from
`bookings@studio.com` uses email.

**Sender identity** is per-project on **both**, but they mean different things: in email it's the
mailbox address you send *from* and receive replies *at*; in notifications it's the display
name/from-address stamped on outbound notifications (`set_sender_identity`). Configuring one does
not configure the other.

Rule of thumb: **no reply expected → notifications. A conversation → email.**

## 1. Provision a mailbox

Instant, on the shared free domain:

```
create_mailbox { "slug": "acme", "displayName": "Acme Studio" }
→ { "mailboxId": "mbx_…", "address": "acme@parsonsapps.com" }
```

On your own domain (the domain must already be **active** in the Domains service — sending and
receiving DNS is provisioned for you):

```
create_mailbox { "slug": "bookings", "domain": "studio.com" }
→ { "mailboxId": "mbx_…", "address": "bookings@studio.com" }
```

Add alias addresses to the same inbox — same mailbox, more doors:

```
create_address { "mailboxId": "mbx_…", "localPart": "support" }
```

Caps: **3 mailboxes** per project, **10 addresses** per project.

## 2. Send and reply

`send_email` opens a thread you can read replies on. Your signature auto-appends; recipient and
daily caps are enforced here.

```
send_email { "mailboxId": "mbx_…", "to": ["customer@example.com"], "subject": "Your booking",
             "body": "Confirmed for Thursday at 4." }
→ { "messageId": "msg_…", "threadId": "thr_…", "status": "sent" }
```

Replying is deliberately two steps, so nothing sends unreviewed:

```
draft_reply { "threadId": "thr_…", "body": "Thursday works — see you then." }  → { "draftId": "dft_…" }
update_draft { "draftId": "dft_…", "body": "…" }        (optional edit)
send_reply { "draftId": "dft_…" }                       → sends it
```

Delivery is not the same as sending — check it:

```
get_delivery_status { "messageId": "msg_…" }
→ { "status": "delivered" | "sent" | "bounced", "detail": "…" }
```

## 3. Read the inbox

```
list_threads { "mailboxId": "mbx_…" }   → newest activity first: subject, participants, count, status
get_thread { "threadId": "thr_…" }      → every message, direction, delivery state, drafts flagged
search_messages { "query": "invoice" }  → full-text over subject, sender, body
move_thread { "threadId": "thr_…", "status": "archived" }   (open | archived | spam)
```

Nothing is ever deleted in v1 — `move_thread` is how mail leaves your view.

## 4. The agent ladder

`set_mailbox_config` sets how much the agent does, and you can climb the ladder as trust grows:

| `agentMode` | Behaviour |
|---|---|
| `off` | Nothing automatic. |
| `triage` | Classifies and labels incoming mail; never writes. |
| `draft` | Writes a draft reply for you to review and `send_reply`. |
| `auto` | Sends replies itself. Turn this on last. |

Same call configures `signature`, a vacation `autoReply {enabled, subject, body, until}`,
`forwardTo` (must be a Cloudflare-verified destination), and `catchallEnabled`.

**Catch-all requires a custom domain.** On the shared domain it would swallow other tenants'
unknown addresses, so it's refused there.

## Notes and limits

- **No public HTTP API on this host.** MCP and the console are the surfaces. A deployed app that
  needs to send mail programmatically goes through notifications'
  `POST /v1/notifications/send` with its `sk_live_` project key.
- Custom-domain mailboxes depend on the **Domains** service; the domain must be active first.
- See [`api.md`](./api.md) for the full action list and argument shapes.
