Reference
CLI
The tinbox command-line tool drives every operation from your terminal or CI — drafting and sending mail, managing audiences and campaigns, importing existing inboxes, and minting API tokens. Most commands map one-to-one to an agent tool.
114 commands
Install & sign in
The CLI ships as the tinbox npm package. Run tinbox login once to authenticate against your deployment; it stores a token for subsequent commands.
# one-off, no install
npx tinbox login
# or install globally
npm install -g tinbox
tinbox loginCommands
Setup & auth
tinbox configShow the resolved config (token redacted)
tinbox inboxesList the inboxes this token can access
tinbox initProvisioning stub — points at the deploy flow
tinbox loginSave api/send URLs + token to ~/.tinbox/config.json (chmod 600)
tinbox whoamiVerify the token works and list accessible inboxes
Drafts & sending
tinbox create-draftCreate a reply DRAFT (never sends on its own — a human reviews and sends, or use send_email if enabled). Provide the inboxId and, for a reply, the threadId. Returns the new draft's id and version.
tinbox draft createCreate a draft (resolves inbox from --thread if --inbox omitted)
tinbox draft exportExport a draft as an outbox/replies/<thread-id>.md working copy (the PR-authoring lane). Frontmatter is stamped with draft_id + draft_version (the CAS base), so merging a stale copy conflicts instead of clobbering.
tinbox draft getShow a draft
tinbox draft listList drafts
tinbox draft sendApprove (→ ready) and send the draft (ledgered, idempotent reply)
tinbox draft updateCompare-and-swap edit a draft (409 → exit 1 + conflict JSON)
tinbox draft versionFreshness probe (PRD §8.3): one indexed read of {version, hash, status}. Probe before acting — pass the version as --base-version on update so a concurrent edit conflicts instead of clobbering.
tinbox draft-all-pendingDraft a personalized cold body for EVERY sourced (not-yet-drafted) prospect in a campaign, in one bounded pass. Moves each sourced → drafted; nothing sends. Returns a tally. Needs a model wired.
tinbox draft-outreach-bodyDraft (or re-draft) one prospect's personalized cold body from the campaign's first sequence-step instruction (or an override) + the prospect's qualification signal. Moves the prospect sourced → drafted; nothing sends. Needs a model wired.
tinbox get-send-readinessCheck whether this deployment can send a given campaign type right now, and if not, exactly what's missing. Returns an ordered checklist per lane (broadcast, outreach, journey) with fix hints and deep-links. Use before creating or launching a campaign to know what to set up first. Pass phase 'send' to treat an empty audience as a hard blocker (would send to 0 people); 'create' is permissive.
tinbox sendSend a message via the sending API (auto idempotency key)
tinbox send-campaignSend an approved campaign immediately to all recipients. This is irreversible — the emails will be sent. Requires the campaign to be in approved status.
tinbox send-readinessAsk the live tenant API for broadcast/outreach/journey readiness
tinbox send-test-campaignSend a one-off test of a campaign draft to a single verified address (e.g. yourself) before the real send. Goes only to that address; it does NOT touch the recipient list or ledger. The natural last check before approve_campaign.
tinbox tokens create-send-keyMint a transactional sending API key (returns plaintext ONCE). Distinct from `tokens create`, which is for inbox-scoped agent/MCP credentials.
tinbox update-draftEdit an existing draft (compare-and-swap on baseVersion to avoid clobbering concurrent edits). Pass the draft id, the baseVersion you last saw, and the fields to change.
Threads & search
tinbox get-activityView recent email activity (sends, receives, bounces) across accessible inboxes. Use to check what happened recently, see delivery statuses, or find sends by a specific origin (API, agent, human).
tinbox get-delivery-statusCheck the delivery status of a specific sent email by its id. Returns the current status, delivery events timeline, and any errors. Use to verify if an email was delivered, bounced, or is still pending.
tinbox get-threadFetch one thread with its full message history (sender, recipients, subject, body) and attachments. Call this to read a conversation before summarizing or drafting a reply.
tinbox list-threadsList recent conversation threads (most recent first). Use to browse an inbox or get an overview. Returns thread summaries with id, subject, participants, and message count.
tinbox search-contactsFind people the user corresponds with — by name or email prefix. Use to resolve a recipient before drafting/sending, or to look someone up. Returns matching contacts (recent correspondents first).
tinbox search-emailsFull-text search the user's mail by subject, sender, or body. Call this to find relevant emails BEFORE answering — never answer from memory about specific mail. Returns matching messages with threadId, inboxId, subject, sender, and a body preview.
tinbox statusDelivery status + event timeline for a send
tinbox summarize-threadSummarize an email thread: who's involved, what they want, the state, and what needs a response. Use when the user asks for a summary or 'what's this about'. Reads the thread, then summarizes.
tinbox threadShow a full conversation (notes flagged as notes)
tinbox threadsList thread summaries (or, with --changed-since, the freshness probe)
Audiences
tinbox add-subscriberAdd or update a subscriber in an audience. If the email already exists, updates their info. Use to subscribe new contacts or update existing ones.
tinbox add-subscriber-channelRegister a delivery channel for a subscriber. type=email|push|webhook. For webhook, endpoint must be an http(s) URL; a signing secret is returned. Optional topics restrict which notification topics this channel receives (e.g. ['order.*']).
tinbox audiences listList audiences with total + subscribed member counts
tinbox audiences membersList an audience's members (paginated; --cursor for the next page)
tinbox create-audienceCreate a new mailing list (audience). The agent can list audiences and add subscribers, but needs this to create the list to add them to. Set the sender identity (fromName/fromEmail) and reply-to.
tinbox get-audienceGet detailed info about a specific audience (mailing list), including subscriber stats by status (subscribed, unsubscribed, pending, cleaned).
tinbox list-audiencesList all mailing list audiences (subscriber lists). Returns each audience's name, subscriber count, and settings. Use before adding subscribers or creating campaigns to find the right audience id.
tinbox list-subscriber-channelsList the notification channels (email/push/webhook) registered for a subscriber (contact). Use to see where a subscriber can be reached before dispatching.
tinbox list-subscribersList subscribers (members) in an audience, optionally filtered by status or tag. Returns email, name, status, and subscription date.
tinbox remove-subscriberUnsubscribe a member from an audience (sets status to unsubscribed). The contact record is preserved for compliance. Use when someone wants to stop receiving emails.
tinbox segments listList an audience's segments with live member counts
tinbox segments previewEvaluate a saved segment now: its live member count + matching member ids
tinbox update-audienceUpdate a mailing list's settings (name, sender identity, reply-to, double opt-in). Partial — only the fields you pass change.
Campaigns
tinbox approve-campaignApprove a campaign for sending (moves from in_review → approved). Requires newsletter:send capability. After approval, the campaign can be scheduled or sent immediately.
tinbox campaigns listList campaigns with per-status recipient counts
tinbox campaigns sendDISPATCH (send now). Two locks (PRD §7.2): the campaign must be approved (content lock) AND your token must hold the `newsletter:send` capability on a write scope (authority lock) — without it: a clear authz error, exit 1. Ledgered + idempotent: a retry re-enqueues only un-sent rows.
tinbox campaigns statusCampaign row + progress + analytics + resolved recipient count (= get + report)
tinbox campaigns testSend a single test of the campaign to one verified address (safe; never touches the recipient ledger; still needs `newsletter:send`)
tinbox create-campaignCreate a COMPLETE email campaign (newsletter) draft in one call: audience (and optional segment), subject, body, sender identity (from/reply-to), a PROPOSED send time, and a short rationale for your choices. The draft lands in the campaign builder for human review — it never sends or schedules itself. Use list_audiences / list_segments first to resolve ids by name, and get_send_readiness('broadcast') before creating.
tinbox create-outreach-campaignCreate a new cold outreach campaign DRAFT. Provide a name and a brief (the ICP / goal prompt that drives sourcing + drafting). Bind the COLD sending domain (`sendingDomainId` + `fromEmail`/`replyTo` on it) — a domain that doesn't exist, or a deployment with no cold BYO-SMTP transport, is REFUSED here with a fix-link (run get_send_readiness('outreach') first to see what's missing). Optionally set `sourcingConfig` to source via a tenant agentic skill (kind:'agentic_skill' + skillId). Starts in draft; nothing sends — source prospects, draft bodies, and review before launch.
tinbox get-campaignGet detailed info about a specific campaign, including content, status, audience, and send progress/analytics.
tinbox get-campaign-reportGet a sent campaign's performance: open/click/unsubscribe analytics plus recipient-ledger progress (sent/pending/failed/suppressed) and the resolved recipient count. Use to answer 'how did my last newsletter do?'. Distinct from get_campaign (which only returns status/content).
tinbox get-outreach-campaignGet one cold outreach campaign's settings (name, brief, sender identity, cold sending domain, daily cap) plus its per-stage rollup (sourced/drafted/approved/denied/sent/replied). Use to inspect a campaign before acting on it.
tinbox list-campaignsList all email campaigns (newsletters). Returns each campaign's title, status, audience, and send progress.
tinbox list-outreach-campaignsList all cold outreach campaigns (the 1:1-at-bulk Campaign surface), newest first, each with its sourced/to-review/sent/replied rollup. Use to find a campaign id before sourcing, reviewing, or launching.
tinbox outreach-campaign-statusGet a cold campaign's sent/replied/qualified rollup — the per-stage funnel (sourced → drafted → approved → sent) plus delivery (bounced/failed/suppressed) and replies. Use to answer 'how is my outreach doing?'.
tinbox personalize-campaignDraft PER-RECIPIENT warm bodies for a campaign from a list of subscribers + their first-party usage stats — the LLM rewrites the body for each. Flips the campaign to per-recipient mode and lands each body in the shared Review queue (drafted). Nothing sends. Needs a model wired.
tinbox schedule-campaignSchedule an approved campaign to send at a specific time. The campaign must be in 'approved' status. Provide a Unix timestamp (milliseconds) for when to send.
tinbox update-campaignUpdate a campaign's settings or content. Only works for campaigns in draft or in_review status. Use to edit subject, content, audience/segment, sender details (from/reply-to/preview text), or move/clear the proposed send time (null clears it).
Templates
tinbox create-templateCreate a new email template. Provide HTML content with optional merge tags like {{contact.name}}, {{contact.email}}, {{urls.unsub}}.
tinbox get-templateGet a specific email template's full content (HTML with merge tags). Use to review or copy template content.
tinbox list-templatesList all email templates available for campaigns. Returns each template's name, preview, and last update time.
tinbox preview-templateRender a template's merge-tag HTML with sample data to see what a recipient would receive. Pass a saved template `id`, or raw `html` to preview an unsaved draft.
tinbox update-templateUpdate an existing email template's name or HTML content.
Importing
tinbox import gmailImport a Gmail mailbox via the Gmail API (format=RAW), using your OWN local OAuth
tinbox import imapImport one IMAP mailbox with a local client (password or app password; OAuth/XOAUTH2 is not supported)
tinbox import mailchimpImport Mailchimp audiences (members/merge fields/tags) and, optionally, past campaigns
tinbox import mboxImport a local .mbox export (Takeout or any client) — zero auth
Tokens & config
Other
tinbox activate-journeyActivate a journey (draft|paused → active). Once active, triggers enroll contacts and the scheduler sends the journey's email steps. The journey must have at least one step. This starts REAL sends — treat like sending a campaign.
tinbox add-forwarding-ruleForward a copy of inbound mail to an external address. matchAddress restricts to one inbound address; omit it to forward ALL inbound mail.
tinbox add-journey-stepAppend a step to a journey (or insert it at `order`). Step types and their `config`: - email: { subject: string, bodyMd?: string } — the email to send. ALWAYS write the body (`bodyMd`, markdown), not just a subject, so the draft is complete and reviewable. - delay: { amount: number, unit: 'minutes'|'hours'|'days' } (wait before the next step) - condition: { conditions: { match: 'all'|'any', rules: [...] }, onPass?: 'continue'|'skip'|'exit', onFail?: 'continue'|'skip'|'exit' } — branch on subscriber attributes or prior-email engagement (rule op 'opened_prev'/'clicked_prev' needs the previous email to be a tracked email step with a delay after it). onPass/onFail route the run: 'continue' = fall through, 'skip' = jump the next step, 'exit' = end the run. Defaults: onPass 'continue', onFail 'exit' (a plain gate). - tag: { tag: string } (apply a tag to the contact) Build the sequence by adding steps in order; the journey must have ≥1 step before it can be activated. If the requested logic can't be expressed (only 4 trigger types; conditions test the immediately-preceding email + segment attributes; branching is continue/skip/exit only, no arbitrary goto), say so in the create_journey `rationale` rather than silently building the wrong graph.
tinbox approve-personalizedBulk-approve (or revert) per-recipient warm bodies by their review-row ids. Approving marks them ready to send on the next campaign send — gated on the newsletter:send capability. This is the content lock for personalized sends.
tinbox approve-prospectsApprove specific prospects (drafted → approved) so they become eligible to send on the next scheduled tick. Capability-gated (outreach:send) AND routed through the HARD cold-domain gate server-side: a prospect can never be approved on a warm/unverified domain. This begins real, irreversible cold sends.
tinbox attachment getDownload one attachment's bytes to disk (token-gated; blocked files 404 → exit 3)
tinbox burn-disposable-mailboxImmediately destroy a disposable mailbox and EVERYTHING in it — the address, the stored mail, and the token (don't wait for expiry). Pass the pollToken. Use drop_disposable_mailbox instead if you only want to stop NEW mail but keep what's there.
tinbox cancel-thread-directiveCancel a thread follow-up directive by id (from list_thread_directives) so it never fires again. The undo for set_thread_directive. Idempotent — canceling an already-canceled or already-fired directive is a safe no-op.
tinbox checkRuntime health check: auth, setup progress, send readiness, recent activity (hits the live API)
tinbox check-sending-domainCheck a domain's live DNS / verification state — re-runs the DNS check now and returns which records are verified (MX/SPF/DKIM/DMARC) and which are still missing, plus whether receiving and sending are valid. Read-only (it changes no config; it just checks). Use to answer 'is my domain verified yet?' during onboarding, or to point the operator at the exact records still to add in Settings → Domains. Give the domain (e.g. yourdomain.com).
tinbox company-briefTrace and summarize the whole relationship with a company (everyone you've emailed at a domain). Use when the user asks 'what's going on with <company>' or 'summarize our relationship with X'. Searches mail from that domain, groups by person, and summarizes.
tinbox create-disposable-mailboxMint a throwaway email address and a pollToken to read its mail with poll_disposable_mailbox. Ideal for grabbing a one-time code (OTP) without touching a real inbox. By default the ADDRESS is kept (a catch-all keeps routing its mail) and the TOKEN never expires — pass expiresIn (e.g. '2h', '30m', '7d') to expire the token, and expireAddress:true to also tear the address down at that time.
tinbox create-inboxCreate ONE new inbox at a mailbox address (e.g. support@yourdomain.com). ORG-ADMIN ONLY and requires a human approval step in chat — the approval card shows the exact address and type before it's created. Use for the onboarding 'set up your first mailbox' step or when the operator asks to add a shared/personal inbox. Provide localPart (the bit before @); domain defaults to the deployment's sending domain. type 'shared' is a team inbox (support@, sales@), 'personal' is one person's. To create a SET of role addresses at once, tell the operator to use Settings → Inboxes presets (this tool creates one at a time).
tinbox create-journeyCreate a new email automation journey (draft) for an audience. A journey is a triggered, multi-step sequence (e.g. a 3-email welcome series). It starts in 'draft' with no steps — add steps with add_journey_step, then activate_journey to turn it on. Optionally set a trigger (e.g. { type: "api_event" } for contacts enrolled via enroll_in_journey, or { type: "signup" }).
tinbox create-segmentSave a multi-condition SEGMENT of an audience (a reusable rule-based slice, e.g. 'members tagged vip who opened the last campaign'). Requires a human approval step in chat — the approval card shows the segment name and how many members currently match (a live preview of the conditions). For a 'saved' segment, provide `conditions` (a match mode + rules); a 'static' segment has none (members are added manually later). To just PREVIEW reach without saving, use preview_segment instead. `newsletter:send` permission is required.
tinbox deny-prospectsReject specific prospects out of the review queue (→ denied). Denying never sends, so it's reversible (re-source or re-draft to bring rows back). Capability-gated (outreach:send) like approve.
tinbox dispatch-notificationDispatch a notification to a subscriber across their active channels matching the topic. payload should include a title and body. Returns per-channel delivery results.
tinbox drop-disposable-mailboxStop NEW mail from arriving at a disposable address (e.g. once a newsletter or signup starts spamming it) while KEEPING the mail already received and the poll token. You can still poll what's there; future mail to the address is rejected. Use burn_disposable_mailbox instead to also delete everything.
tinbox enroll-in-journeyEnroll a contact into an api_event journey by contact id or email — the manual trigger. The journey must be active. Ledger-safe: it only enrolls (the send happens on the next scheduler tick). A non-reentrant duplicate is a no-op (enrolled:false).
tinbox get-handbookRead the team handbook — the operator's standing policies (plain-language lines like 'Never email competitor domains'). Returns every active entry with its id, text, topic, source, and creation time; pass `topic` to filter to one section. Use it to check what standing behavior applies before acting, or when the user asks what's in the handbook. Read-only.
tinbox get-journeyGet one journey with its ordered steps (email/delay/condition/tag) and trigger. Use before editing, activating, or enrolling contacts.
tinbox get-setup-stateCheck how set up this deployment is and what's left to configure. Returns the ordered onboarding checklist — every milestone (add a sending domain, verify DNS, confirm inbound routing, create an inbox, receive/send the first email, enable the assistant, invite the team) with its state (done | pending | blocked), a fix hint, and a deep link to the exact settings pane. Use this to answer 'what's left to set up?' and to walk the operator through remaining steps ONE at a time. For 'can I send a campaign right now?' use get_send_readiness instead. Read-only; never fabricate DNS or dashboard steps — take them from this tool's hints.
tinbox launch-outreachLaunch a cold campaign (review → approved) — the content lock that makes its approved prospects dispatchable. Capability-gated (outreach:send) AND routed through the HARD cold-domain gate: a campaign whose from/reply-to isn't on a VERIFIED cold subdomain is rejected. Actual sends fire on the scheduled tick (throttled + ramped). Irreversible: begins real outreach.
tinbox list-forwarding-rulesList inbound forwarding rules — which inbound addresses forward a copy to which external destinations.
tinbox list-journeysList email automation journeys (triggered multi-step sequences like welcome series or drips), newest first, with each journey's status, step count, and per-status run counts. Use to discover journeys before inspecting, editing, activating, or enrolling contacts.
tinbox list-personalized-reviewRead the per-recipient review queue for a personalized warm campaign — each subscriber's drafted (or approved) body. Use to review the rewritten bodies before approving them to send.
tinbox list-review-queueRead the ranked review queue for a cold campaign — every prospect (optionally one stage), hottest-first by qualification score, with whether each has a drafted body. Use to review what's ready before approving prospects to send.
tinbox list-segmentsList an audience's SAVED segments (rule-based and static) with live member counts. Use to resolve a segment by name (e.g. 'active customers') before targeting a campaign at it via segmentId. For an ad-hoc, unsaved condition check use preview_segment instead.
tinbox list-thread-directivesList the follow-up directives on a thread — the reply logic attached to it (trigger, mode, status, how many times it's fired, when it expires). Read-only; use it to check what will happen when a reply lands before setting or canceling one.
tinbox outreach-replies-digestA reply-intent triage summary for a cold campaign: how many prospects replied (of how many sent), with a pointer to the Inbox where the actual reply conversations live (the one place an AI summary of intent earns its keep). Use to triage 'who replied to my outreach?'.
tinbox pause-journeyPause an active journey (active → paused). Existing runs freeze and no new contacts enroll until it's activated again. The off-switch for activate_journey.
tinbox pause-outreachHold a cold campaign mid-sequence (→ paused). Resumable — no prospects are lost; sending stops until resumed. Reversible.
tinbox poll-disposable-mailboxRead the mail that has arrived at a disposable mailbox, newest first (returns ALL messages — a fresh box holds under 10). Pass the pollToken from create_disposable_mailbox. Use format='simplifiedMD' or 'otpOnly' to get a one-time code fast: any code the OTP skill detected is surfaced first.
tinbox preview-segmentCount and sample the subscribers in an audience that match a set of conditions, WITHOUT saving a segment. Lets you reason about reach before composing a campaign (e.g. 'how many active subscribers tagged VIP?'). `conditions` is { match: 'all'|'any', rules: [{ field, op, value }] }.
tinbox search-imagesFind stock images (or generate an AI placeholder) for a campaign or newsletter body. mode='search' queries the okslop stock library by keyword; mode='generate' returns a deterministic AI-generated placeholder for a prompt (use when nothing fits or you need a hero image). Returns image URLs you can drop into markdown as . Read-only — picking an image is your job; nothing is inserted or sent.
tinbox set-thread-directiveAttach follow-up logic to a thread: when a reply arrives (or after a delay), the platform drafts/sends/asks/notifies per your instructions. Use it when the user wants a standing reply plan on a conversation ('if they reply, draft an answer in my voice'; 'remind me if no reply in 3 days'). `trigger`: 'reply' fires on the next inbound; 'no_reply_after'/'after' are timers (set `after` like '3d'/'7d'). `action.mode`: 'draft' (default — lands in Review), 'send' (auto-sends, if the deployment permits; otherwise downgraded to a draft), 'ask' (parks a check-in question), 'notify' (notification only). Cancel with cancel_thread_directive.
tinbox setup-statusShow setup checklist progress (first-run milestones)
tinbox skills listList the tenant/plugin agentic skills the assistant can call, with their secret-gating + enabled state
tinbox skills runInvoke one agentic skill on your deployment (scoped env/fetch/caller applied server-side). Input is a JSON object.
tinbox source-prospectsSource + qualify prospects into a cold campaign WITHOUT sending. Resolve a candidate set from explicit org domains and/or a Contacts search (plus the campaign's stored sourcing config), run the GTM qualifier over each, and persist the qualified rows (idempotent per recipient). Writes sourced rows only — no email goes out.
tinbox update-handbookRecord, edit, or archive a standing policy in the team handbook. Use this when the user states a standing preference or corrects your behavior ('from now on…', 'always…', 'never…'): propose the exact one-line wording, get their confirmation, THEN call this with op:'add'. Never record anything silently. If the new preference contradicts an existing line (check get_handbook), use op:'edit' on that line's entryId instead of adding a duplicate. op:'archive' retires a line that no longer applies. Reversible: nothing is ever hard-deleted — an add is undone by archive, an edit by another edit. `entryId` accepts the full id or the short [hbk_*] handle.