posthorn
v0.2.11
Published
Domain setup, mailbox creation, and email warmup from the command line
Maintainers
Readme
Posthorn
Posthorn spins up cold-email infrastructure: sending domains, mailboxes, SPF/DKIM/DMARC, and inbox warmup. It runs on accounts you own and is drivable entirely by an AI agent.
It's a pure orchestration layer: you own your Cloudflare account, your Google Workspace, your domains, and your mailboxes. Posthorn automates the setup and warmup on top of accounts you control. It never owns or bills for any of it.
Quick start with an AI agent (recommended)
Posthorn is built to be driven by an agent (Claude Code, Codex, Cursor, etc.). Paste this into your agent:
I want to set up cold-email infrastructure: sending domains, mailboxes, and inbox warmup. Use the Posthorn CLI to do it. First run
npm install -g posthornthenposthorn guide, read the guide, and walk me through the whole setup step by step. Run the commands for me and tell me whenever I need to do something in my browser.
The agent reads posthorn guide (which prints this document) and orchestrates
the rest.
Install
npm install -g posthornOr run any command without installing via npx posthorn <command>.
Agent playbook
If you're an AI agent driving the posthorn CLI for a user, this is the
knowledge you need that --help alone doesn't give you. Read it fully before
starting. Run posthorn guide any time to reprint it.
The platform is a pure orchestration layer: the USER owns their Cloudflare account, their Google Workspace, their domains, and their mailboxes. Posthorn never owns or bills for any of it.
The flow: walk it like a setup wizard
Go step by step. Ask one question at a time, only when the step needs it, and do as much as possible yourself. Don't front-load questions.
Step 1. posthorn auth register. Instant API key; no email or signup info
needed, and there are no account tiers. Nothing to ask.
Step 2. Domain. Ask: "Do you need a new domain for your emails, or will you use an existing one for sending?"
- NEW domain (the purchase always happens on the user's own Cloudflare account
and card; Posthorn never owns or bills for domains):
a. They need a Cloudflare account with a payment method (they pay Cloudflare
directly for the domain, ~$10/yr). Browser step: create the API token
(below), then
posthorn accounts cloudflare <token>. b.posthorn domains check name1.com name2.io --cloudflare <id>(availability- price) →
posthorn domains reputation <pick>(vets Spamhaus blocklist, reputation score, and prior use; verdicts: clean / caution / avoid. Run it before buying; you can't tell a tainted domain from its name.) →posthorn domains buy <pick> --cloudflare <id> --contact '{...}'
- price) →
- EXISTING domain. If it runs their live website or real email, recommend a
dedicated sending domain instead. Two ways to connect it; either way the
domain stays registered where they bought it, only nameservers change:
a. Their own Cloudflare: they manage the domain's DNS in their own Cloudflare
account. Needs the API token (below); and if the domain isn't on their
Cloudflare yet, they add it at dash.cloudflare.com and point nameservers
there first. Then
posthorn domains connect <domain> --cloudflare <id>. b. Posthorn-managed DNS: no Cloudflare account to create or manage; Posthorn hosts the domain's DNS for them (free).posthorn domains managed <domain>→ they set the 2 printed nameservers at their registrar →posthorn domains activate <id>. Note: Posthorn then hosts ALL of the domain's DNS records (website records included), so it fits domains dedicated to email.
Step 3. Google Workspace. Ask: "Do you have a Google Workspace you can add new domains and mailboxes to, or do you want to set up a new one?"
- Existing Workspace: delegation browser step (below), then
posthorn accounts workspace <admin-email>. - New Workspace: walk them through the signup (browser step below: "Creating a new Google Workspace org"), then delegation. Tell the user the org signup is also one-time; it gets reused for every future domain and mailbox. (Delegation is per org, not per domain, so with an existing org this step can happen any time, even before the domain exists. The domain pipeline auto-adds and verifies the new domain inside their org.)
Step 4. Wait for the domain: poll posthorn domains get <id> until status
ready (minutes to 24h; poll every 30-60s, don't hammer). MX/SPF/DMARC are
configured automatically. Statuses progress: pending_* → purchased →
dns_configuring → dns_configured → dns_verified → workspace_verifying →
workspace_verified → ready.
Step 5. DKIM. Browser step below; once per domain, needs the domain ready.
Step 6. posthorn mailboxes create <domain-id> --email ... --first ... --last ...
Step 7. posthorn warmup start <mailbox-id>
Dependencies: you CANNOT create a mailbox until the domain status is ready.
Run posthorn auth status --json any time to see where things stand. State is
stored locally, so you can stop and continue any time.
The external/manual steps (things that happen OUTSIDE the CLI)
These are the steps you must GUIDE THE USER through in their browser. Give exact click-by-click instructions. Before each browser step, share with the user that this is a one-time setup, e.g. "This is a one-time setup step; you won't need to do this again." The repetition model, so you can answer follow-ups:
- Cloudflare API token: once ever
- Workspace signup (only when creating a new org): once ever
- Workspace delegation: once per Workspace org
- DKIM: once per domain
- Everything else (domains, mailboxes, warmup): fully automated, no browser
Cloudflare API token (one-time, for "buy new" or "own Cloudflare" domains)
- Tell the user: "This is a one-time setup; you won't need to do this again."
- dash.cloudflare.com/profile/api-tokens → Create Token → Custom Token
- Permissions: Account>Account Settings>Read, Account>Registrar: Domains>Admin, Zone>Zone>Edit, Zone>DNS>Edit.
- Account Resources: Include > All accounts
- Zone Resources: Include > All zones
- Do NOT add Billing permissions; they are not needed. Domain purchases charge the payment method already on the Cloudflare account, which is a dashboard setting, not a token permission.
- Then:
posthorn accounts cloudflare <token> - This token is only for Cloudflare (domains and DNS). Google Workspace is NOT connected with this token; it has its own separate one-time step below (domain-wide delegation, no token involved).
- For domain PURCHASES, the user also needs a payment method on their Cloudflare account (they pay Cloudflare directly; Posthorn never bills for domains).
Creating a new Google Workspace org (only when the user has none)
Tell the user: one-time, about 5 minutes, needs a credit card (Business Starter is ~$7/user/month with a free trial). Walk them through workspace.google.com → Get started:
- Business name, employee count, region. Any values are fine.
- Current email: any email they already read (personal Gmail is fine; it's just the contact for signup).
- When asked about a domain, choose the option saying they ALREADY HAVE a domain, and enter the sending domain from step 2 of the flow. Do NOT buy a domain from Google here, even if offered: the domain must stay at their registrar/Cloudflare so Posthorn can manage its DNS.
- Create the admin user, e.g. admin@. This account is the
org's SUPER-ADMIN: they should save the password, and this is the email
for
posthorn accounts workspace <admin-email>later. - Pick Business Starter, add payment, finish signup.
- If Google prompts to VERIFY the domain or set up MX records, skip it ("I'll do this later" / close the wizard). Posthorn does domain verification and MX automatically once delegation is set up.
- Continue to domain-wide delegation (next section), signed in as that new super-admin.
Google Workspace domain-wide delegation (one-time per Workspace org)
- Tell the user: "This is a one-time setup for your Workspace; you won't need to do this again."
- admin.google.com → Security → Access and data control → API controls → Domain-wide delegation → Add new
- Client ID: 110137377718772968374
- OAuth scopes (paste all, comma-separated):
https://mail.google.com/,https://www.googleapis.com/auth/admin.directory.user,https://www.googleapis.com/auth/admin.directory.domain,https://www.googleapis.com/auth/siteverification - Must be done signed in as a SUPER-ADMIN of that Workspace org, and the email
passed to the CLI must be that super-admin's. Then run:
posthorn accounts workspace <admin-email> - This replaces OAuth entirely: no consent screen, no app verification, no test users.
Nameservers (only for "managed DNS" or moving a domain to Cloudflare)
- The CLI prints 2 nameservers. The user sets them at their domain REGISTRAR (where they bought the domain), replacing the existing nameservers.
- Propagation takes minutes to 24h. Check with
posthorn domains activate <id>(managed) or by pollingposthorn domains get <id>.
DKIM (per domain, Google has no DKIM API)
Tell the user: "This is a once-per-domain step; new mailboxes on this domain won't need it." If you have browser-automation tools, do it for the user:
- Navigate to https://admin.google.com/ac/apps/gmail/authenticateemail (the URL may need /u/N/ for the right account slot, verify the "Selected domain" on the page matches).
- If status is "Authenticating email with DKIM" → already done, skip.
- Otherwise click GENERATE NEW RECORD → GENERATE (defaults: 2048-bit, "google" prefix). Read the TXT record value (starts with v=DKIM1; k=rsa; p=...).
- Add it to DNS as a TXT record named google._domainkey..
- Click START AUTHENTICATION on the admin page. If no browser tools: have the user do the above and paste you the TXT value, then add it to their DNS.
Mailboxes & sending
- Create:
posthorn mailboxes create <domain-id> --email [email protected] --first John --last SmithReturns a one-time password (Google Workspace login). Save it (not shown again). - Credentials for IMAP/SMTP are auto-provisioned via the service account (domain-wide delegation). Google mailboxes need no per-mailbox setup.
- Send:
posthorn send <mailbox-id> --to [email protected] --subject "Hi" --body "..."
There is no email-verification step anywhere: connecting your own Cloudflare and Workspace IS the identity. Once a mailbox exists, sending and warmup work.
Warmup
posthorn warmup start <mailbox-id>→ joins the shared warmup pool and runs continuously until paused- Volume and reply behavior are platform-managed (ramps from 2/day up to 5/day, then holds; peers reply to ~30% of warmup mail). Not configurable: the pool is shared, so settings are tuned for everyone's deliverability.
posthorn warmup stats <campaign-id>→ placement rate, reputation, daily breakdownposthorn warmup list→ all campaigns- Warmup never fully stops on its own, pause with
posthorn warmup pause <id>.
Feedback (bugs, feature requests)
posthorn feedback --type bug|feature|question|other "<message>"
If you hit a bug, missing capability, or rough edge while driving this CLI, report it; it goes straight to the Posthorn team. Agents: you are encouraged to file feedback yourself when something doesn't work the way you expected (include the command you ran and what you expected).
Whenever you or the user get stuck, file the issue with posthorn feedback.
Tips for agents
- Read commands auto-detect output: when stdout isn't a TTY (i.e. you're an agent
capturing output), they emit JSON automatically, no flag needed. Humans in a
terminal get formatted text. Force either way with
--json/--pretty. - Every command stores state locally (~/.config), so the user doesn't re-enter keys.
- Translate everything into plain English for the user. Never show them raw JSON or ask them to run curl, you run the CLI on their behalf.
