The Lumail CLI lets you manage your email marketing directly from the terminal. It uses the same SDK as the TypeScript library, so every operation available in the SDK is also available via CLI.

## Installation

```bash
npm install -g lumail
```

Or run without installing:

```bash
npx lumail <command>
```

## Create an account with an AI agent

Coding agents cannot use interactive prompts. Start a session and follow the
printed next command every time:

```bash
npx lumail start --agents
# Now you need to give us the email.
#   npx lumail start --session start_xxx --email you@domain.com

npx lumail start --session start_xxx --email ada@example.com
# Now you need to give us the 6-digit sign-in code.
#   npx lumail start --session start_xxx --otp 123456

npx lumail start --session start_xxx --otp 123456
# Now you need to give us the website or the organization name.
#   npx lumail start --session start_xxx --website lumail.io
#   npx lumail start --session start_xxx --org "Ada Labs"

npx lumail start --session start_xxx --website lumail.io --org "Ada Labs"
# Now you need to give us the sending domain.
#   npx lumail start --session start_xxx lumail.io

npx lumail start --session start_xxx lumail.io
# Now add the DNS records, then verify.
#   npx lumail start --session start_xxx --verify-domain

npx lumail start --session start_xxx --verify-domain
# Now you need to give us the default sender.
#   npx lumail start --session start_xxx --sender hello

npx lumail start --session start_xxx --sender hello
# Now install Lumail for your detected AI agents.
#   npx lumail start --session start_xxx --install-agents
```

`--agents` prints a session id. Each step exits with the exact next command.
Skip a later step with `--skip-domain`, `--skip-verify`, or `--no-agents`.
`--json` returns the same `session`, `step`, `hint`, and `next` fields.

A real terminal can still run the interactive one-shot:

```bash
npx lumail start
```

Useful options:

| Option               | Effect                                               |
| -------------------- | ---------------------------------------------------- |
| `--session <id>`     | Continue this agent onboarding session               |
| `--agents`           | Start a session and print the first next command     |
| `--email <email>`    | Account email                                        |
| `--otp <code>`       | 6-digit email code                                   |
| `--org <name>`       | Organization name                                    |
| `--website <domain>` | Brand website, same as `/orgs/new`                   |
| `--domain <domain>`  | Sending domain; a positional domain also works       |
| `--sender <local>`   | Default from-address local part, e.g. `hello`        |
| `--no-sender-domain` | Finish account and agent setup without a domain      |
| `--no-agents`        | Skip skill and MCP installation                      |
| `--no-agent-auth`    | Configure MCP clients without opening their OAuth UI |
| `--account <name>`   | Save and reuse this as a named Lumail account        |

Re-running `start` is safe. A valid login is reused, existing domains are read
back instead of recreated, and agent JSON configuration is merged without
removing unrelated servers.

`start` is an onboarding command, not an MCP server. Never register
`npx lumail start` itself as an MCP command; it configures the remote
`https://lumail.io/mcp` connection.

## Authentication

Browser OAuth is recommended because tokens refresh automatically:

```bash
lumail auth login
```

You can still save an API key manually:

```bash
lumail auth set lum_your_api_token_here
```

Get your API token from **Settings > API Tokens** in your Lumail dashboard, or follow the [API Tokens guide](/docs/api-reference/api-tokens).

```bash
# Show saved token (masked)
lumail auth show

# Show full token
lumail auth show --raw

# Verify token works
lumail auth test

# Remove saved token
lumail auth remove
```

The token is stored at `~/.config/lumail/token` with restricted file permissions.

After a browser sign-in, mint a durable `lum_` token for an app:

```bash
lumail auth login
lumail tokens create --name "In-app integration"
```

`tokens create` defaults to App permissions (`subscribers`, `emails`,
`audience`). Pass `--full`, `--preset marketing|sender|full`, or
`--permissions subscribers,audience`. Reuse requires the same name and the
same permission set.

## Sender domains

Create or resume a sender domain and print its DNS records plus an agent-ready
setup prompt:

```bash
lumail domain setup example.com
```

After DNS propagation, verify by domain name or the returned domain ID:

```bash
lumail domain verify example.com
lumail domain verify domain_123
```

The verification command reads back the authoritative Lumail/SES state and
prints every remaining DNS record with its current status.

## AI-agent integration

To install or repair only the skill and MCP connections, without repeating
account or domain onboarding:

```bash
lumail setup
lumail setup --authenticate
```

`--authenticate` opens OAuth for clients with a supported CLI. Windsurf requests
OAuth the first time the Lumail MCP connection is used.

## Named Accounts

Use named accounts when you manage multiple organizations from the same machine:

```bash
lumail accounts add lumail lum_your_api_token_here
lumail accounts add client-a lum_client_api_token_here
```

Then run any command with `-a` or `--account`:

```bash
lumail subscribers list -a lumail
lumail campaigns list --account client-a
```

Named account tokens are stored at `~/.config/lumail/accounts.json` with restricted file permissions. Commands without `-a` keep using the legacy token from `lumail auth set`, so no migration is required.

```bash
# List saved named accounts
lumail accounts list

# Show a named account token (masked)
lumail accounts show lumail

# Show the full token
lumail accounts show lumail --raw

# Remove a named account
lumail accounts remove lumail
```

## Global Flags

Every command supports these flags:

| Flag                         | Description                            |
| ---------------------------- | -------------------------------------- |
| `-a, --account <name>`       | Use a named API key account            |
| `--json`                     | Output as JSON                         |
| `--format <text\|json\|csv>` | Output format (default: text)          |
| `--verbose`                  | Enable debug logging                   |
| `--no-color`                 | Disable colored output                 |
| `--no-header`                | Omit table headers (useful for piping) |

```bash
# Get JSON output
lumail campaigns list --json

# CSV for spreadsheets
lumail subscribers events user@example.com --format csv

# Pipe to jq
lumail campaigns list --json | jq '.data.campaigns[].subject'
```

## Subscribers

### Create or update

```bash
lumail subscribers create --email user@example.com --name "John Doe" --tags vip newsletter
lumail subscribers create --email buyer@example.com --tags course-bought --skip-double-opt-in
```

### Get details

```bash
lumail subscribers get user@example.com
lumail subscribers get sub_abc123
```

### Update

```bash
lumail subscribers update user@example.com --name "Jane Doe"
lumail subscribers update user@example.com --tags premium --replace-tags
```

### Unsubscribe

```bash
lumail subscribers unsubscribe user@example.com
```

### Manage tags

```bash
# Add tags
lumail subscribers add-tags user@example.com --tags vip premium

# Remove tags
lumail subscribers remove-tags user@example.com --tags old-tag
```

### List events

```bash
lumail subscribers events user@example.com
lumail subscribers events user@example.com --take 50 --order asc
```

## Campaigns

### List campaigns

```bash
lumail campaigns list
lumail campaigns list --status DRAFT
lumail campaigns list --query "welcome" --limit 50
```

### Create

```bash
lumail campaigns create --subject "Welcome!" --name "Welcome Campaign"
```

### Get details

```bash
lumail campaigns get <campaign_id>
```

### Update (DRAFT only)

```bash
lumail campaigns update <campaign_id> --subject "Updated Subject" --preview "New preview"
```

### Delete (DRAFT only)

```bash
lumail campaigns delete <campaign_id>
```

### Send or schedule

```bash
# Send immediately
lumail campaigns send <campaign_id>

# Schedule for later
lumail campaigns send <campaign_id> --scheduled-at 2025-12-25T10:00:00Z --timezone UTC
```

## Tokens

Mint organization API tokens after `lumail auth login`. These are the durable
`lum_` secrets you put in `LUMAIL_API_KEY` — the OAuth session itself is not
an app token.

```bash
# App preset (subscribers, emails, audience)
lumail tokens create --name "In-app integration"

# Full access
lumail tokens create --name "ops" --full

# Always mint a new secret
lumail tokens create --name "CI" --no-reuse

# List tokens (last-4 and permissions)
lumail tokens list
```

## Tags

```bash
# List all tags
lumail tags list

# Create a tag
lumail tags create --name "premium"

# Get tag details
lumail tags get premium

# Rename a tag
lumail tags update <tag_id> --name "gold"
```

## Emails (Transactional)

### Send an email

```bash
lumail emails send \
  --to user@example.com \
  --from noreply@yourdomain.com \
  --subject "Order Confirmation" \
  --content "Your order #1234 has been confirmed." \
  --content-type MARKDOWN
```

Prints `{ message, id }` (`id` is `eml_<dispatchId>`, same as `GET /v1/emails/:id`). JSON mode wraps that in `{ ok: true, data }`.

Options: `--reply-to`, `--transactional`, `--content-type` (MARKDOWN, HTML, TIPTAP)

### Verify an email

```bash
lumail emails verify user@example.com
```

## Events

```bash
lumail events create \
  --type SUBSCRIBER_PAYMENT \
  --subscriber user@example.com \
  --data '{"amount": 99, "plan": "pro"}'
```

## Tools (V2 API)

Access every tool available to the current organization from the terminal. Workflow tools are included for every organization:

```bash
# List all tools
lumail tools list

# Get tool schema
lumail tools get list_subscribers

# Run a tool
lumail tools run list_subscribers --params '{"limit": 10}'
lumail tools run create_campaign --params '{"name": "Test", "subject": "Hello"}'

# Inspect the Workflow setup contract before building a complete draft
lumail tools get configure_workflow_draft

# Discover and inspect Workflow groups before assignment
lumail tools run list_workflow_groups --params '{}'
lumail tools get set_workflow_group
```

### Workflow group example

```bash
lumail tools run create_workflow_group \
  --account my-org \
  --params '{"name":"Onboarding","conflictStrategy":"SKIP_NEW"}'

lumail tools run set_workflow_group \
  --account my-org \
  --params '{"workflowId":"workflow-id","expectedUpdatedAt":"2026-07-27T10:00:00.000Z","groupId":"group-id"}'
```

Always use `--account <org>` for organization-scoped Workflow work. Read the live schema with `tools get`, then read resources again after mutation. Publishing, status changes, workflow deletion, and group deletion use the confirmation-code flow.

See [Tools API (v2)](/docs/api-reference/v2-tools) for the full list of available tools.

## Examples

### Bulk tag subscribers

```bash
for email in alice@example.com bob@example.com charlie@example.com; do
  lumail subscribers add-tags "$email" --tags "webinar-2025"
done
```

### Export subscribers as CSV

```bash
lumail tools run list_subscribers \
  --params '{"limit": 1000, "status": "SUBSCRIBED"}' \
  --format csv > subscribers.csv
```

### Quick campaign workflow

```bash
# Create
ID=$(lumail campaigns create --subject "Flash Sale!" --name "Flash Sale" --json | jq -r '.data.campaignId')

# Send
lumail campaigns send "$ID"
```

## Related Documentation

- [TypeScript SDK](/docs/api-reference/sdk) - Programmatic API client
- [API Tokens](/docs/api-reference/api-tokens) - Generate your API key
- [MCP Server](/docs/api-reference/mcp) - AI agent integration
- [Tools API (v2)](/docs/api-reference/v2-tools) - All available tools
