Skip to content
NewSee how
cli

Sending Domains From the CLI: Check DNS Before Launch

Sending domains CLI guide: verify tracking domains, SPF, DKIM and DMARC with FirstSales commands before any campaign starts.

TL;DR: The FirstSales CLI does not write your DNS records, and that is a feature. It reads and verifies them: tracking-domains verify, email-auth status, email-auth verify and warmup status give you a pass or fail answer you can script before any campaign starts.


#The CLI verifies domains and does not configure them

Most guides about sending domains tell you what DNS records to add. This one makes a narrower and more useful claim: a terminal is the best place to check whether those records work.

The FirstSales command line interface (CLI) has no command that writes a DNS record at your registrar. It has commands that ask FirstSales what it sees, and that difference shapes the whole workflow.

You add the records at your DNS provider. You then use firstsales tracking-domains verify, firstsales email-auth status and firstsales email-auth verify to confirm that the world sees what you intended.

That split is healthy for an agent. A coding assistant should not hold the keys to your DNS zone, but it can safely run read-only checks and tell you which record is wrong.

The stakes are real. Google's email sender guidelines require SPF, DKIM and DMARC authentication for anyone who sends more than 5,000 messages a day to Gmail accounts, and they tell senders to keep the spam rate below 0.10%.

A domain with a broken record fails quietly at first, then loudly. A scripted check turns that slow failure into a failing exit code on the day you set up the domain.

This post covers the domain commands in the CLI, what each one proves, what it cannot prove, and how to combine them into a gate that runs before any campaign starts.

All IDs here, such as org_123, ws_123 and domain_123, are placeholders. Never paste a real API key into a prompt or a script you commit.

#Which domain commands exist

The CLI package is @firstsales.io/cli and the binary is firstsales. As of October 2026 the published version is 0.1.11.

Five command groups touch domains. The table lists them with the kind of change each can make.

GroupSubcommandsWhat it is for
tracking-domainslist, get, create, delete, verifyCustom domain for link and open tracking
email-authstatus, verifySPF, DKIM and DMARC state for a sending domain
warmupstatusWarm-up state for a connector
connectorslist, create (cal-com only), delete, test, and update commandsConnected accounts
domainslist, add, removeOrg-level domain list
blocked-domainslist, add, removeDomains you must never email

Run firstsales commands --json to see the registry for your installed version. The package skill treats that registry as the authority, so trust it over any article.

The reference for every command lives in the FirstSales CLI reference.

#Three kinds of domain, three different jobs

The word "domain" covers three separate things in an outbound setup, and mixing them up causes most of the confusion.

#The sending domain

This is the domain in the From address, such as mail.example.com. Mailbox providers judge your reputation by it, and SPF, DKIM and DMARC are published for it.

The choice between your main domain and a separate one is a strategy decision. The post on subdomain versus separate domain covers it, and how many sending domains cold email needs covers the count.

#The tracking domain

This is the domain used to rewrite links, and to serve open pixels if you track opens. It is a different hostname from your sending domain, and it needs its own DNS record and its own certificate.

A tracking domain that shares reputation with your main site can drag that site down. A dedicated tracking hostname keeps the damage contained.

#The domain allowlist

The README describes the domains group as "domain allowlist automation." It is an organization-level list, separate from tracking and sending.

I will treat this as a list-management feature and avoid guessing its exact policy effects, because the README documents the commands and not the semantics. Read the live API contract before relying on it.

#Start with a safe session

Install the package and check it.

bash
npm i -g @firstsales.io/cli firstsales --help

Set the key in the environment and confirm who you are before you read anything.

bash
export FIRSTSALES_API_KEY="<YOUR_FIRSTSALES_API_KEY>" firstsales whoami --json firstsales doctor --pretty

whoami validates the key and prints the organization and workspace context without exposing the raw or hashed key. doctor checks your setup.

Every command in this post is a read except tracking-domains create, tracking-domains delete, domains add and domains remove. Those four change state, and delete and remove are destructive.

#A key with the least access

A domain check script needs read access and little else. Create a dedicated key for it so a leak cannot do real damage.

bash
firstsales api-keys create \ --org org_123 \ --data '{"name":"Domain checker","scopes":["<READ_SCOPES_ONLY>"],"accessLevel":"workspace"}' \ --json

Take the exact scope names from the OpenAPI contract at developer.firstsales.io, not from this post. The raw key is shown once, so put it in a secret manager immediately.

Never paste that key into a Claude Code prompt. Export it in your shell and let the tool read the environment variable.

For a longer treatment of scoping, the post on API keys for outbound agents goes deeper.

#Tracking domains from the terminal

Start by listing what exists.

bash
firstsales tracking-domains list --org org_123 --workspace ws_123 --json

Read one entry in full.

bash
firstsales tracking-domains get --org org_123 --workspace ws_123 --domain domain_123 --json

The get response includes certificateEligibility. In the CLI README, a value of lookup_failed is the example of a state that means the lookup behind the certificate check did not succeed.

That is a diagnostic field, not a verdict. A lookup_failed result usually points at DNS that has not propagated yet or a record that points somewhere unexpected.

#Verify

The command that matters most is verify.

bash
firstsales tracking-domains verify --org org_123 --workspace ws_123 --domain domain_123 --json

The README lists this exact form as an example. It asks FirstSales to check the tracking domain against the DNS it can see right now.

Run it after you add the record, not before. DNS changes take time to spread, so a failed check in the first few minutes is expected, and you should wait and retry.

#Create

Creating a tracking domain is a state change, so preview it first. The tracking-domains create command takes a JSON body.

bash
firstsales tracking-domains create --org org_123 --workspace ws_123 --data-file tracking-domain.json --dry-run

I cannot tell you the exact body fields, because the README names the command and not its schema. Run --dry-run and read the OpenAPI contract for the request shape.

--dry-run prints the method, URL, redacted headers and body without sending the request. It does not use auth or the network.

If you are unsure, ask for help first.

bash
firstsales tracking-domains create --help

After creation, add the DNS record your provider needs, wait, and run verify.

#Delete

Deleting a tracking domain is destructive. The command needs the --confirm flag, and the action cannot be undone.

bash
firstsales tracking-domains delete --org org_123 --workspace ws_123 --domain domain_123 --confirm

Treat this like any other delete. Do not let an agent run it without a human reading the exact command first.

Links in emails you already sent still point at the old hostname. Removing the domain can break those links for the people who received them.

#Email authentication: SPF, DKIM and DMARC

Authentication is where most setup failures live, and the CLI gives you two commands for it.

bash
firstsales email-auth status --org org_123 --workspace ws_123 --json

The status command reports the state of your sending domain's email authentication. The verify command checks a specific domain and selector.

bash
firstsales email-auth verify --domain acme.com --dkim-selector s1 --org org_123 --workspace ws_123 --json

This is the exact example from the README. Replace acme.com with your sending domain and s1 with the DKIM selector you published.

#What each protocol proves

SPF, defined in RFC 7208, lets a domain publish which servers may send for it. Receivers compare the connecting server against that list.

DKIM, defined in RFC 6376, signs each message with a key whose public half lives in DNS. The selector tells receivers which key to fetch.

DMARC, defined in RFC 7489, ties the two together. It tells receivers what to do when a message fails both checks, and it asks them to report back.

Alignment is the part people miss. A message passes DMARC only when SPF or DKIM passes and the passing domain matches the visible From domain.

The full setup lives in SPF, DKIM and DMARC setup for 2026, which covers the records themselves.

#What email-auth verify cannot tell you

A passing verify proves the records exist and validate for that domain and selector at the moment of the check. It does not prove that Gmail or Outlook will deliver your mail to the inbox.

Inbox placement also depends on reputation, content, list quality and sending pace. For placement, use an inbox placement seed list and watch Google Postmaster Tools.

#A realistic failure sequence

Here is the pattern I would expect on a new domain, described as a sequence and not as a captured output.

You publish SPF and DKIM, but forget DMARC. email-auth verify flags the missing record, you add a DMARC policy of p=none, and you run it again.

Then you wait for reports and tighten the policy later. Going straight to p=reject on day one is risky, because a misaligned legitimate sender would start bouncing.

#Warm-up status

New mailboxes need a gradual ramp. The CLI exposes warm-up state through warmup status, and it takes a connector.

bash
firstsales warmup status --org org_123 --workspace ws_123 --connector connector_123 --json

Check the flag name against firstsales warmup status --help, because the README lists the command and the connector input without a worked example.

Use the result as a gate. A mailbox that has not finished warming should not carry a full campaign load.

The ramp itself is a deliverability topic. Ongoing email warm-up explains why warming never ends, and emails per inbox per day gives sensible daily caps.

#Warm-up is not a substitute for authentication

A warmed mailbox on a domain with broken DKIM still lands in spam. Check authentication first, then check warm-up.

The order matters in a script too. Authentication failures are cheap to fix, and warm-up failures need days.

#Connectors and what the CLI leaves to the app

A connector is a connected account, such as a mailbox or a calendar. The connectors group has list, create, delete, test and update commands.

bash
firstsales connectors list --org org_123 --workspace ws_123 --json firstsales connectors test --org org_123 --workspace ws_123 --connector connector_123 --json

connectors list shows what is connected. connectors test checks that a connector works. Connector secrets are never returned in either response.

#CLI connector creation is cal-com only

The CLI's command list shows connectors create with a single supported type: cal-com. That is the calendar connector used for booking.

From that, I draw a careful conclusion. The CLI does not appear to connect mailboxes, so you connect sending mailboxes in the FirstSales app.

I flag this as an inference, not a documented statement. Check firstsales connectors create --help and the live command registry for your version before telling a teammate that mailbox setup is app-only.

#Sender profile and settings

The update commands cover display name, sender profile and settings: update-display-name, update-sender-profile and update-settings. They change how a connector appears to recipients.

Preview any of them with --dry-run. A wrong display name goes out on every message until someone notices.

Delete is destructive, so it needs --confirm, and it cannot be undone.

#The org-level domains list

The domains group has list, add and remove. The README example shows the add form.

bash
firstsales domains add --org org_123 --data '{"domain":"example.com"}' --json

Treat the group as organization-level, because the command takes --org and no workspace in the example. That is a different scope from the workspace-level tracking domains.

domains remove is destructive. It needs --confirm, and you should read the exact domain before you run it.

I will not claim what the allowlist enforces, because the README documents the commands and not the policy behind them. Check the API contract if the list drives a decision in your setup.

#The order of the checks

The checks depend on each other, so the order matters. The diagram shows the sequence this post recommends, and every arrow is labeled with the condition that moves you forward.

flowchart TD
    A[whoami and doctor] -- identity confirmed --> B[email-auth verify]
    B -- SPF, DKIM, DMARC pass --> C[tracking-domains verify]
    B -- fail --> X[Fix records at DNS provider]
    C -- verified --> D[connectors test]
    C -- fail --> X
    D -- connector works --> E[warmup status]
    D -- fail --> Y[Reconnect in the app]
    E -- warm enough --> F[campaigns readiness]
    E -- still warming --> Z[Wait and lower volume]
    X -- wait for propagation --> B

Authentication sits first because it is the cheapest to fix and the most damaging to ignore. Warm-up sits late because it can only be fixed with time.

#A pre-launch domain script

The script below combines the read-only checks into one gate. It uses only commands from the README and the CLI's command list, and it relies on exit codes instead of parsing fields I cannot see.

bash
#!/usr/bin/env bash set -u ORG="org_123"; WS="ws_123" SENDING_DOMAIN="acme.com"; DKIM_SELECTOR="s1" TRACKING_DOMAIN_ID="domain_123"; CONNECTOR="connector_123" fail=0 run() { echo "== $*" "$@" code=$? if [ "$code" -ne 0 ]; then echo "FAILED with exit code $code: $*" >&2 fail=1 fi } run firstsales whoami --json run firstsales email-auth verify --domain "$SENDING_DOMAIN" --dkim-selector "$DKIM_SELECTOR" --org "$ORG" --workspace "$WS" --json run firstsales tracking-domains verify --org "$ORG" --workspace "$WS" --domain "$TRACKING_DOMAIN_ID" --json run firstsales connectors test --org "$ORG" --workspace "$WS" --connector "$CONNECTOR" --json run firstsales warmup status --org "$ORG" --workspace "$WS" --connector "$CONNECTOR" --json if [ "$fail" -ne 0 ]; then echo "Domain gate failed. Do not start campaigns." >&2 exit 1 fi echo "Domain gate passed. Run campaigns readiness next."

Read the exit-code table before you rely on it. The CLI returns 0 for ok, 1 for a runtime error, 2 for usage, 3 for auth, 4 for not found and 5 for rate limited.

One caveat is important. A command can exit 0 and still report a failed verification inside its JSON body, depending on how the API models a failed check.

I cannot confirm which way verify behaves without running it, so test the script against a domain you know is broken before you trust it. That one test is worth more than the rest of the script.

#What the gate does not cover

The script proves infrastructure. It does not prove that the campaign is ready, that the copy is safe or that the list is clean.

Those checks belong to campaigns readiness and campaigns send-test-email, which you must run before campaigns start. The post on the pre-launch checklist from the terminal shows how to chain them.

#What the rules require in 2026

Authentication is not optional for volume senders. The numbers below come from the providers themselves.

RuleGoogle (Gmail)Microsoft (Outlook.com)
Threshold for bulk sender statusMore than 5,000 messages per day to personal accounts5,000 or more emails per day
SPF, DKIM, DMARC required✓✓
One-click unsubscribe for marketing mail✓Not stated in the cited post
Spam rate guidanceKeep below 0.10%, never reach 0.30%Not stated in the cited post
Enforcement startRules from 2024, tightened sinceMay 5, 2025

Google documents the thresholds in its sender guidelines. Microsoft documents its requirements in the Microsoft Defender for Office 365 blog.

Microsoft's post says that starting May 5, 2025, non-compliant mail from high-volume senders is rejected with the error "550 5.7.515 Access denied, sending domain [your domain] does not meet the required authentication level."

Other details on this are in our posts on Google's bulk sender rules and the Outlook 5,000 sender rules.

One more consideration applies to every campaign you send. The one-click unsubscribe header standard is RFC 8058, and one-click unsubscribe for cold email explains how to meet it.

#Why a script beats a dashboard

A dashboard shows you the state when you look. A script runs every time, in the same order, and does not forget the step you skip when you are in a hurry.

Pre-flight checklists work this way in other fields. The 2009 New England Journal of Medicine study by Haynes and colleagues found that a 19-item surgical safety checklist cut the inpatient death rate from 1.5% to 0.8% across eight hospitals (NEJM, 2009).

An outbound domain is not an operating room. The lesson still carries: a short written checklist beats memory under pressure.

#Let Claude Code run the checks

Claude Code can run the domain gate without holding your DNS credentials. That is the safe shape of this workflow.

The package ships three skills for agents: firstsales-cli, firstsales-product-mcp and firstsales-developer-api. The CLI skill tells an agent to verify identity first, read before mutating and prefer --json.

#A prompt that keeps the agent in its lane

You are checking domain health for FirstSales workspace ws_123 in org org_123. Allowed: whoami, doctor, tracking-domains list/get/verify, email-auth status/verify, warmup status, connectors list/test. Not allowed without my explicit yes: tracking-domains create/delete, domains add/remove, connectors create/delete/update-*, any api-keys command. Use the FIRSTSALES_API_KEY environment variable and never print it. Report each failing check with the command, the exit code and the next step I should take at my DNS provider.

The prompt names allowed reads, blocks writes and keeps the key out of the conversation. It also asks the agent to tell you what to do at your DNS provider, which is where the real fix happens.

#What a good agent report looks like

A useful report is short. It names the check that failed, shows the command, and states the single next action.

For example, "DKIM verify failed for selector s1 on acme.com. Publish the TXT record at your DNS provider, wait for propagation, then re-run the verify command." That is enough.

Compare it with a report that says "domain issues found." The second one gives you nothing to act on.

#The human-in-the-loop rule

The Model Context Protocol tools specification says there "SHOULD always be a human in the loop with the ability to deny tool invocations." The same instinct applies to shell commands that change domains.

Allow reads freely. Prompt for writes, and always prompt for deletes.

For the guardrail patterns in detail, see guardrails for email-sending agents.

#Where MCP fits

The FirstSales Product MCP server is firstsales-product, a streamable HTTP server at https://api.app.firstsales.io/mcp. It uses OAuth, and it does not accept Developer API keys.

The tool list depends on your tenant and your grant, so call tools/list and read what your account exposes. This post does not assume any domain tool exists in MCP.

Domain verification and tracking domain changes belong with the CLI. Use MCP when you want an assistant to read campaign data and talk about it.

The package skill states the rule plainly: if an action is mutating, destructive, billing-related or approval-backed, use the CLI or Developer API instead of assuming MCP support.

For help picking between the surfaces, read CLI, MCP or the app: which for which job and what MCP is for sales teams.

#Common mistakes

Domain setups fail in predictable ways. Most are avoidable with one extra command.

#Running verify before DNS has propagated

A failed check minutes after you add a record often means the world has not seen it yet. Wait, then retry, instead of editing the record again.

#Editing the wrong zone

Records added at a registrar do nothing if your nameservers point elsewhere. Add them where your authoritative DNS lives.

#Forgetting the DKIM selector

email-auth verify takes --dkim-selector for a reason. A verify against the wrong selector fails even when the key is published.

#Treating a passing verify as inbox placement

A pass proves the records. It does not prove reputation. Test placement separately and watch the metrics.

#Sharing one tracking hostname with the main site

If link reputation drops, you want the damage to stay on a dedicated hostname. Give tracking its own domain.

#Skipping warm-up on a new mailbox

A fresh mailbox at full volume looks like a spammer. Check warmup status and ramp slowly.

Old emails keep their links. Deleting the hostname breaks them, and the deletion cannot be undone.

#Putting the API key in a prompt

Keys leaked through prompts end up in transcripts and logs. Keep the key in the environment and create a read-only one for checks.

For the larger picture of what goes wrong when domains fail, read email deliverability monitoring and deliverability incident response.

#What a good domain routine looks like

A routine beats a one-time setup. Domains drift, certificates expire and people edit DNS for unrelated reasons.

Run the gate before every launch. Run a lighter version, email-auth status and tracking-domains list, on a schedule so you catch drift between launches.

Write down who owns the DNS zone. When a check fails at 9 a.m. on a Monday, you want to know whom to message.

Keep a short log of changes. A line with the date, the record and the reason saves hours when something breaks.

#When to rotate domains

Sometimes a domain's reputation falls and does not recover. The post on email domain rotation explains when to retire a domain and how to do it without panic.

The CLI helps with the checking side of that work. It cannot decide to retire a domain for you, and it should not.

#How to read a failed check

A failed check is information, and the fastest way to use it is to ask three questions in order. What did the command test, what does the DNS say right now, and what changed since the last pass?

#Start with what you can see

Use a plain DNS lookup from your own terminal to compare what FirstSales reports with what the public DNS returns. The standard tools dig and nslookup read TXT and CNAME records without any account access.

If the public record is missing, the fix is at your DNS provider. If the record is present and the check still fails, the problem is usually a typo, a wrong selector or a record published on the wrong hostname.

#Look for the common typos

DKIM records are long, and some DNS panels split or truncate them. A key that lost its last few characters validates as broken even though it looks fine at a glance.

SPF has a limit of ten DNS lookups, defined in RFC 7208. Adding one more included service can push a working record over the limit and turn a pass into a permanent error.

#Wait before you retry

Cached answers can linger for as long as the record's time to live. If you lowered the time to live before the change, the wait shrinks, which is a good habit before any planned DNS edit.

Write down the time you changed the record. A retry ten minutes later with a clear timestamp beats five retries in a row with no notes.

#Escalate with evidence

If a check still fails after you have confirmed the public record, save the command, the exit code and the JSON output to a file. Hand that file to whoever owns the DNS zone or to FirstSales support.

Evidence turns a vague "domains are broken" message into a ticket someone can close in one reply.

#A handover note for your team

Domain setup tends to live in one person's head. A short note makes the next person's day easier.

Record the sending domain, the DKIM selector, the tracking domain ID, the connector IDs and the date of the last passing gate. Add the name of whoever owns the DNS zone.

Keep the note in your repository next to the gate script. Never write the API key in it, and never include DNS provider passwords.

Review the note whenever you add a domain. The five minutes it takes keeps the script and the facts in sync.

If an agent runs the gate for you, give it the note as context. It can then name the exact selector and domain without guessing.

#FAQs

#Does the FirstSales CLI write DNS records for me?

No. The CLI verifies what FirstSales can see, and you add records at your DNS provider. The commands for checking are tracking-domains verify, email-auth status and email-auth verify.

#Which command checks SPF, DKIM and DMARC?

firstsales email-auth verify --domain <domain> --dkim-selector <selector> checks a domain and selector, and email-auth status reports the current state.

#What is a tracking domain?

It is a custom hostname used for link rewriting and open tracking, separate from your sending domain. A dedicated hostname keeps link reputation away from your main site.

#How do I verify a tracking domain?

Run

firstsales tracking-domains verify --org <org> --workspace <workspace> --domain <domain-id>
after you add the DNS record. If it fails right away, wait for propagation and retry.

#What does lookup_failed mean in certificateEligibility?

It means the lookup behind the certificate eligibility check did not succeed. Usually the DNS record is missing, wrong or not yet propagated.

#Can the CLI connect a mailbox?

The command list shows connectors create supports cal-com only, so mailbox connection appears to happen in the FirstSales app. Confirm against firstsales connectors create --help for your version.

#How do I check warm-up progress?

Run firstsales warmup status with the connector. Check --help for the exact flag, because the README names the command without a worked example.

#Is deleting a tracking domain reversible?

No. tracking-domains delete needs --confirm and cannot be undone. Links in emails you already sent will point at the removed hostname.

#Should an AI agent run tracking-domains create?

Not on its own. Preview with --dry-run, read the request, and have a human approve it, because the change affects every link you send.

#What is the difference between domains and tracking-domains?

tracking-domains is workspace-level and handles link tracking hostnames. domains is organization-level, and the README calls it domain allowlist automation.

#What are the Google requirements for bulk senders?

Google requires SPF, DKIM and DMARC for senders of more than 5,000 messages a day to Gmail accounts. It also tells senders to keep the spam rate below 0.10% and never let it reach 0.30%.

#What are the Microsoft requirements?

Microsoft requires SPF, DKIM and DMARC for senders of 5,000 or more emails a day to Outlook.com, with enforcement starting May 5, 2025. Non-compliant mail can be rejected.

#Does a passing email-auth verify guarantee the inbox?

No. It proves the records validate. Placement also depends on reputation, content and list quality.

#Which exit code means the command was not found?

Exit code 4 means not found. The full set is 0 ok, 1 runtime, 2 usage, 3 auth, 4 not found and 5 rate limited.

#Can I script the domain checks?

Yes. The CLI is JSON-first and returns stable exit codes. Test your script against a domain you know is broken before you trust it.

#How often should I run domain checks?

Run the full gate before each launch, and a lighter check on a schedule to catch drift. A weekly cron job with email-auth status is a reasonable start.

#What key should a check script use?

A dedicated key with read access only, created with api-keys create. The raw key appears once, so store it in a secret manager.

#Can MCP verify my domains?

Do not assume it. The Product MCP tool list is per tenant and per grant, so check tools/list. Use the CLI for verification.

#What should I run after the domain gate passes?

Run campaigns readiness and campaigns send-test-email before campaigns start. The domain gate does not replace them.

#What does --dry-run do?

It prints the method, URL, redacted headers and body without sending the request. It uses no auth and no network.


#Conclusion

Domain setup is where outbound programs quietly succeed or fail, and the CLI turns that setup into something you can check the same way every time.

The takeaways from this post are short.

  • The CLI verifies domains and does not write DNS. Add records at your DNS provider, then check them with tracking-domains verify and email-auth verify.
  • Authentication comes first, then warm-up, then the campaign gate. campaigns readiness and campaigns send-test-email still run before every campaigns start.
  • A passing verify proves records, not placement. Watch spam rate and bounces after you send.
  • Give scripts a read-only key, keep keys out of prompts, and treat tracking-domains delete, domains remove and connector deletes as actions that cannot be undone.
  • Test your gate against a deliberately broken domain once, so you know a failure looks like a failure.

To try it, install the CLI with npm i -g @firstsales.io/cli, run firstsales whoami --json, and run email-auth verify on your sending domain. Then read the pre-launch checklist from the terminal and how to start, pause and resume campaigns to finish the launch path.

Keep reading

Outreach that keeps going after you log off.Leads, emails, follow-ups and replies, handled.

Connect unlimited mailboxes and let AI agents find leads, write each email and follow up. Or send your own templates in manual mode. From $29/mo.

$1 for 3 days · Cancel anytime · No contract

Install with AI

Your coding agent sets up the FirstSales CLI and skills for you.

Prompt for Claude Code

I'm setting up FirstSales (https://firstsales.io), an AI outbound sales platform: campaigns, contacts, a reply inbox, deliverability and lead signals. Help me get my workspace sending real, good emails end to end, from Claude Code.

Read these first so you know how FirstSales works:
- Developer docs and API: https://developer.firstsales.io
- CLI: https://www.npmjs.com/package/@firstsales.io/cli
- Skills for coding agents: https://github.com/firstsalesio/firstsales-skills (read README.md and GUIDE.md)

Setup
1. Install the CLI: npm install -g @firstsales.io/cli
2. Install the FirstSales skills:
   claude plugin marketplace add firstsalesio/firstsales-skills
   claude plugin install firstsales@firstsales
3. Ask me if I already have a FirstSales account. If not, send me to https://app.firstsales.io to sign up.
4. Ask me to create an API key under Settings → API → API Keys, with only the scopes we need.
   Never ask me to paste the key into this chat. Tell me to run this in my own terminal, so the key stays hidden:
   read -rs FS_KEY && firstsales auth login --api-key "$FS_KEY"; unset FS_KEY
5. Run `firstsales whoami` and tell me which workspace and organisation we are connected to.

Then ask me about my business: what I sell, who I sell to (roles, company size, countries), my best customers, and what I use today for outbound (tools, lists, mailboxes). Walk me through:
1. Teaching FirstSales my business: website, offer, proof points and case studies in the knowledge base, so the AI writes like someone who knows the product.
2. Connecting my sending mailboxes and checking my sending domain: SPF, DKIM, DMARC and warm-up. If anything is unhealthy, tell me the exact DNS record to add.
3. Bringing in contacts: import my CSV or CRM export into a clean list, remove duplicates and bad emails, and block domains I must never email (customers, competitors, my own).
4. Building my first campaign: the right list, senders, steps and timing. Write the sequence with me, show me the drafts, and do not launch until I say yes.
5. Setting up Signals if it fits: find people engaging with LinkedIn posts about topics my buyers care about, and turn them into leads.
6. Inviting my team and giving each person the right access.

Once campaigns run, show me how to work the reply inbox from here: which replies need an answer, draft responses in my voice, and move good conversations into deals. If I use Cal.com, connect it so follow-ups can offer my booking link (not the first email).

Throughout, as you learn about my business, proactively suggest and help create:
- Reply templates for the questions and objections my prospects are likely to raise, based on my product, site and codebase if you can see them.
- Campaign ideas and segments worth testing, with the reason for each.

Safety rules:
- Show every change as a dry run (--dry-run) first and wait for my yes. Never send emails, launch campaigns or delete anything without my yes.
- Tell me before anything that spends credits, and how many.

Be opinionated. If the docs give a sensible default, just use it. Don't make me choose between five options.