> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getcargo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> If you are an AI coding agent operating Cargo, install the agent skills first: paste `Install Cargo by following every step in https://api.getcargo.io/agent-install.txt` into your session, or run `npx skills add getcargohq/cargo-skills`. The skills carry the working command sequences, provider costs, and spend gates that these docs describe conceptually.
> The skills index at https://github.com/getcargohq/cargo-skills/blob/main/llms.txt lists every skill, recipe, and provider playbook individually. Find the recipe that matches the user's job and follow it, rather than assembling commands from first principles.
> Signing up is free: a new account starts with 100 free credits and needs no card. `cargo-ai login --email you@company.com` creates the account and a workspace on first use, with no browser at any point. Tell the user this before asking them to sign up.
> Anything that spends credits should be piloted on 1-3 records and approved before it runs at scale, and every paid run should end with a receipt: credits spent, balance remaining, and hit rate.

# Overview

> Owned sending domains and mailboxes for outbound email. Register a domain with defineDomain, provision mailboxes with defineMailbox, and send from plays and tools with sendEmail.

A **mailbox** is an inbox Cargo owns and sends from — `jane@acme-outreach.com`, not a connected Gmail or Outlook account. Mailboxes live on a **sending domain** you register through Cargo. You send from them with the native `sendEmail` action, the same way a play calls `allocate` or a connector action.

There is no HTTP "send" route. Delivery is a native action so workflows reuse orchestration's pacing, retries, and credit charge. Direct delivery would skip all three.

## How the pieces fit

```mermaid theme={null}
flowchart LR
  D["defineDomain"] --> M["defineMailbox"]
  M --> W["Warm-up"]
  W --> S["sendEmail in a play or tool"]
  S --> T["Thread + events"]
```

1. **Register a domain** with [`defineDomain`](#register-a-sending-domain) (or buy one in the UI).
2. **Declare mailboxes** on that domain with [`defineMailbox`](#declare-a-mailbox). Google, shared, or private inboxes.
3. **Start warm-up** so the daily send ceiling can climb from 5 to 40 over 45 days.
4. **Send** from a [play](/plays/overview) or [tool](/tools/overview) with `sendEmail({ mailboxUuid: jane.uuid, … })`. Orchestration spaces those sends across the day and refuses once the rolling 24-hour allowance is spent.
5. **Watch the thread** — opens, clicks, replies, and unsubscribes land as events on the conversation.

See [Sending](/mailboxes/sending) for pacing, warm-up, and the `sendEmail()` helper, and [Using the UI](/mailboxes/using-ui) for the same flow in the app.

## Register a sending domain

A mailbox can only be created on a domain the workspace already owns and that is **active**. `defineDomain` is the CDK resource for that:

```ts domains/outreach.ts theme={null}
import { defineDomain } from "@cargo-ai/cdk";

// Bind a domain already bought in the Cargo UI. destroy then releases it
// rather than cancelling a registration the deploy never paid for.
export const outreach = defineDomain("acme-outreach.com", { adopt: true });
```

Omit `adopt` to **register** a new domain through Cargo. Registration charges workspace credits and is not refundable — a `+ create domain:…` line in `cargo-ai cdk plan` is the signal, and the deploy confirmation is where it's approved.

```ts theme={null}
export const outreach = defineDomain("acme-outreach.com", {
  dnsRecords: [
    { type: "MX", name: "@", value: "mail.mailpool.io", priority: 10 },
    { type: "TXT", name: "@", value: "v=spf1 include:mailpool.io ~all" },
  ],
});
```

<Warning>
  `dnsRecords` is the **whole zone**, not a patch. Declaring it replaces every
  live record, including the ones the registrar wrote at purchase. Leave it off
  to manage only the domain's lifecycle and let the zone be edited elsewhere.
  `[]` empties the zone.
</Warning>

A freshly registered domain sits at `pending` while the registrar provisions it. The deploy waits until it is `active` before publishing DNS or creating mailboxes.

The domain is addressed by its name, the way a member is addressed by email. If the workspace already owns that name and the spec does not say `adopt: true`, deploy fails with the way out (`cargo-ai cdk import` or `adopt: true`) rather than buying it a second time.

## Declare a mailbox

`defineMailbox` provisions an inbox on that domain. Pass the domain handle — the deploy waits until the domain is active, creates the mailbox, and waits until the provider has issued credentials so a play in the same graph can send.

```ts mailboxes/jane.ts theme={null}
import { defineMailbox } from "@cargo-ai/cdk";

import { outreach } from "../domains/outreach";

export const jane = defineMailbox("jane", {
  domain: outreach,
  type: "google",
  firstName: "Jane",
  lastName: "Doe",
});
```

That yields `jane@acme-outreach.com`. The slug is the CDK identity (`mailbox:jane`); `username` defaults to the slug. When two inboxes share a local part on different domains, pick a unique slug and set `username` explicitly:

```ts theme={null}
export const janeSales = defineMailbox("jane_sales", {
  domain: sales,
  type: "google",
  username: "jane",
  firstName: "Jane",
  lastName: "Doe",
});
```

`jane.uuid` is a deferred token. Pass it to `sendEmail` the same way you pass a capacity handle to `allocate`:

```ts theme={null}
sendEmail({
  mailboxUuid: jane.uuid,
  to: input.email,
  subject: "Quick note",
  bodyHtml: "<p>Hi</p>",
});
```

| Field                    | Meaning                                                                                                   |
| ------------------------ | --------------------------------------------------------------------------------------------------------- |
| `domain`                 | A `defineDomain` handle or `domainRef("uuid")`. Must be **active** before the mailbox is created.         |
| `type`                   | `google`, `shared`, or `private` (SMTP). `outlook` cannot be provisioned — Graph delivery has not landed. |
| `username`               | Local part of the address. Defaults to the slug. Letters, digits, dots, dashes, underscores.              |
| `firstName` / `lastName` | Used as the From display name. Reconciled on every deploy.                                                |
| `signature`              | Optional HTML stored on the mailbox. Omit to leave whatever is live; declare it to set it.                |
| `folder`                 | Optional [folder](/folders/overview) of kind `mailbox`.                                                   |
| `adopt`                  | Bind an inbox the workspace already owns at `username@domain` instead of provisioning a new one.          |

The workspace must have credits on file. Creating a mailbox charges a **monthly** fee in credits for as long as it exists (Google 125, shared and private 100). A send then charges **0.1 credits** per delivered email. `destroy` deletes a mailbox the CDK created (and stops the fee); an adopted mailbox is released, never deleted.

Provisioning is asynchronous. A new mailbox starts `pending` and becomes `active` once the provider has issued credentials. The deploy waits for that, the same way it waits for a domain registration. Only an `active` mailbox can send. Auth failure or a spam flag from the provider moves it to `inactive` and sending stops immediately.

Domain, username, and type are create-only. Changing them is a destroy plus a new `defineMailbox`. If the workspace already owns that address and the spec does not say `adopt: true`, deploy fails with the way out rather than provisioning a second inbox.

A mailbox created in the UI (or by an earlier deploy whose state file was lost) is bound the same way as a domain:

```ts theme={null}
export const jane = defineMailbox("jane", {
  domain: outreach,
  type: "google",
  firstName: "Jane",
  lastName: "Doe",
  adopt: true,
});
```

## Organize with folders

Mailbox folders are a separate namespace from model or agent folders. Declare one with `defineFolder` and pass the handle:

```ts folders/outreach.ts theme={null}
import { defineFolder, defineMailbox } from "@cargo-ai/cdk";

import { outreach } from "../domains/outreach";

export const mailboxFolder = defineFolder("outreach-mailboxes", {
  kind: "mailbox",
  name: "Outreach",
});

export const jane = defineMailbox("jane", {
  domain: outreach,
  type: "google",
  firstName: "Jane",
  lastName: "Doe",
  folder: mailboxFolder,
});
```

## What a mailbox is not

Cargo mailboxes are not a replacement for [Resend](/integration/resend), [SendGrid](/integration/sendgrid), or [Lemlist](/integration/lemlist). Those remain connector actions against *your* ESP or sequencer. A Cargo mailbox is an inbox the workspace owns, warmed and paced so cold outreach from a new domain does not burn the domain's reputation.

## From the CLI

Prefer `defineMailbox` for the inbox itself. Use the CLI for warm-up, allowance, threads, events, and suppressions — the same surface as the [mailbox management API](/api-reference/introduction).

```bash theme={null}
cargo-ai mailboxManagement mailbox list
cargo-ai mailboxManagement mailbox get 550e8400-e29b-41d4-a716-446655440000
cargo-ai mailboxManagement mailbox get-send-allowance 550e8400-e29b-41d4-a716-446655440000
cargo-ai mailboxManagement mailbox start-warmup 550e8400-e29b-41d4-a716-446655440000
cargo-ai mailboxManagement thread list --mailbox-uuid 550e8400-e29b-41d4-a716-446655440000
cargo-ai mailboxManagement suppression create --email opted-out@acme.com
```

Ad-hoc sends still go through orchestration, so they pick up the same rate limit and credit charge as a play:

```bash theme={null}
cargo-ai orchestration action execute \
  --action '{"kind":"native","actionSlug":"sendEmail","config":{}}' \
  --data '{"mailboxUuid":"<uuid>","to":"lead@acme.com","subject":"Hello","bodyHtml":"<p>Hi</p>"}' \
  --wait-until-finished
```
