Lumail command-line interface for managing subscribers, campaigns, emails, tags, events, and tools from your terminal.
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.
npm install -g lumail
Or run without installing:
npx lumail <command>
Coding agents cannot use interactive prompts. Start a session and follow the printed next command every time:
npx lumail start --agents
# Now you need to give us the email.
# npx lumail start --session start_xxx --email [email protected]
npx lumail start --session start_xxx --email [email protected]
# Now you need to give us the 6-digit sign-in code.
# npx lumail start --session start_xxx --otp 123456
--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:
npx lumail startUseful 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.
Browser OAuth is recommended because tokens refresh automatically:
lumail auth loginYou can still save an API key manually:
lumail auth set lum_your_api_token_hereGet your API token from Settings > API Tokens in your Lumail dashboard, or follow the API Tokens guide.
# 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 removeThe token is stored at ~/.config/lumail/token with restricted file permissions.
After a browser sign-in, mint a durable lum_ token for an app:
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.
Create or resume a sender domain and print its DNS records plus an agent-ready setup prompt:
lumail domain setup example.comAfter DNS propagation, verify by domain name or the returned domain ID:
lumail domain verify example.com
lumail domain verify domain_123The verification command reads back the authoritative Lumail/SES state and prints every remaining DNS record with its current status.
To install or repair only the skill and MCP connections, without repeating account or domain onboarding:
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.
Use named accounts when you manage multiple organizations from the same machine:
lumail accounts add lumail lum_your_api_token_here
lumail accounts add client-a lum_client_api_token_hereThen run any command with -a or --account:
lumail subscribers list -a lumail
lumail campaigns list --account client-aNamed 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.
# 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 lumailEvery 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) |
# Get JSON output
lumail campaigns list --json
# CSV for spreadsheets
lumail subscribers events [email protected] --format csv
# Pipe to jq
lumail campaigns list --json | jq '.data.campaigns[].subject'lumail subscribers create --email [email protected] --name "John Doe" --tags vip newsletterlumail subscribers get [email protected]
lumail subscribers get sub_abc123lumail subscribers update [email protected] --name "Jane Doe"
lumail subscribers update [email protected] --tags premium --replace-tagslumail subscribers unsubscribe [email protected]# Add tags
lumail subscribers add-tags [email protected] --tags vip premium
# Remove tags
lumail subscribers remove-tags [email protected] --tags old-taglumail subscribers events [email protected]
lumail subscribers events [email protected] --take 50 --order asclumail campaigns list
lumail campaigns list --status DRAFT
lumail campaigns list --query "welcome" --limit 50lumail campaigns create --subject "Welcome!" --name "Welcome Campaign"lumail campaigns get <campaign_id>lumail campaigns update <campaign_id> --subject "Updated Subject" --preview "New preview"lumail campaigns delete <campaign_id># Send immediately
lumail campaigns send <campaign_id>
# Schedule for later
lumail campaigns send <campaign_id> --scheduled-at 2025-12-25T10:00:00Z --timezone UTCMint 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.
# 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# 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"lumail emails send \
--to [email protected] \
--from [email protected] \
--subject "Order Confirmation" \
--content "Your order #1234 has been confirmed." \
--content-type MARKDOWNPrints { 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)
lumail emails verify [email protected]lumail events create \
--type SUBSCRIBER_PAYMENT \
--subscriber [email protected] \
--data '{"amount": 99, "plan": "pro"}'Access every tool available to the current organization from the terminal. Workflow tools are included for every organization:
# 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_grouplumail 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) for the full list of available tools.
for email in [email protected] [email protected] [email protected]; do
lumail subscribers add-tags "$email" --tags "webinar-2025"
donelumail tools run list_subscribers \
--params '{"limit": 1000, "status": "SUBSCRIBED"}' \
--format csv > subscribers.csv# Create
ID=$(lumail campaigns create --subject "Flash Sale!" --name "Flash Sale" --json | jq -r '.data.campaignId')
# Send
lumail campaigns send "$ID"