Here's the goal: Harvey finds businesses in the area you sell to, reads their websites, keeps the ones that fit, and drafts a short cold email about something real it saw on their site. When somebody replies, it drafts the next answer and keeps steering the thread toward a call on your calendar. And out of the box, nothing goes out until you approve it.
Harvey is a free, open-source tool on GitHub (MIT license). It does its thinking on your Claude Pro or Max plan through Claude Code, so there's no per-email AI bill and nobody in the middle taking a fee. What it does need is the boring stuff the lazy cold emailers skip: a separate domain to send from, a mailbox that's warmed up, and an email checker so it only writes to real addresses. I'd rather you spend an afternoon on that than burn your main domain in a week. This guide walks through all of it, a free test first, and what breaks.
Start here: paste this into Claude Code
Open a terminal, download Harvey and start Claude Code inside its folder. Then paste the prompt below. It walks you through every step in this guide one at a time, has you paste your own keys into a file (never into the chat), runs a small free test, and stops before anything costs money or reaches a real person.
git clone https://github.com/ethanplusai/harvey.git
cd harvey
claudeHi Claude. Please be my patient setup helper. I run a small business and I'm not technical: one step at a time, tell me exactly what to type or click, and wait for me after each step.
Goal: set up Harvey (the open-source sales tool in this folder, https://github.com/ethanplusai/harvey) so it finds businesses that fit what I sell, reads their websites, and drafts cold emails and replies on my Claude plan. Every email waits in Harvey's Outbox for my approval. We are not sending anything to anyone today.
Steps:
1. Check what's installed: python3 --version (Harvey needs Python 3.11 or newer) and claude --version. If my Python is too old, tell me how to get Python 3.13 for my computer and stop.
2. Install Harvey in this folder: make a virtual environment (a private copy of Python just for Harvey) with Python 3.11 or newer, activate it, run pip install -e . and check that harvey --help works. On a Mac use python3.13 -m venv .venv, never the plain python3 that came with the Mac.
3. Ask me what I already have: a separate domain just for cold email (never my main one), a Google Workspace mailbox on it, and whether SPF, DKIM and DMARC are set up (three DNS records that prove my mail really comes from me). For anything missing, walk me through it one record at a time. Buying a domain or a mailbox costs money, so I decide.
4. Mailbox: walk me through a Google Cloud project with the Gmail API turned on, the Google Auth platform set up with the audience Internal, and an OAuth client of type Desktop app. Then copy .env.example to .env and have me open .env and paste GMAIL_CLIENT_ID and GMAIL_CLIENT_SECRET in myself. Make sure channels.email.provider is gmail. Then I run harvey gmail auth in my own terminal (it opens a browser sign-in) and harvey gmail test.
5. Email checker: help me get a free Reoon key, and I paste it into .env as REOON_API_KEY myself. Without a checker, every address stays a guess and Harvey never sends to it.
6. Train Harvey on my website: harvey train followed by my site's address. Then go through harvey.local.yaml with me, one part at a time: persona (my real name and my sending address), product, product.offer.goal (book_call) and product.offer.booking_url (my calendar link), icp (the industries, job titles and cities I sell to), compliance.postal_address (my real mailing address), compliance.do_not_contact (my customers and competitors), channels.email.max_daily_sends (20 to start) and channels.email.require_approval (must stay true). Ask me before you change anything.
7. Signals: run harvey signals, explain the list in plain words, then run harvey signals --confirm free so it only collects what costs nothing.
8. Free test: harvey discover --estimate --city "<my city, ST>" and show me the estimate. Then harvey discover --city "<my city, ST>" --limit 20 on the free OpenStreetMap source. Then harvey warmup, and explain READY or NOT READY.
9. Tell me how to start the dashboard (harvey dashboard) and Harvey (harvey run) in two terminal windows of my own. Explain the Outbox: A approves, R rejects, E edits. Remind me not to approve anything until harvey warmup says READY.
House rules for this setup:
- If you use a technical word, explain it in plain English the first time.
- Ask me before you assume anything about my business, my accounts or my setup.
- Stop and check with me before anything that costs money: a domain, a mailbox, a warmup plan, a paid lead source.
- Stop and check with me before anything that sends, posts or publishes to real people. Never approve an email in the Outbox, never run harvey outbox --approve-all, and never turn on autopilot.
- Stop and check with me before you delete or overwrite anything, including .env and harvey.local.yaml.
- Never ask me for, print or save a password, key or token. I paste keys into .env myself, you don't read .env, and you never print the dashboard link's token.How the pieces connect
This is the manual way: every step and every command. Claude follows it too.
- 1Findharvey discover (OpenStreetMap by default, free)→ businesses in your cities and industries
- 2Read their siteHarvey's profiler: three web requests per business, no AI→ facts like their agency, their ads, no online booking, a stale blog
- 3Pick the fitsThe signals you confirmed + the cohort builder→ a list where you know why each one is on it
- 4Find who decidesTheir own team and about pages + your email checker→ a checked address, or no email at all
- 5WriteClaude, on your Claude plan, with Harvey's writing rules→ a 3-email sequence about something real
- 6You approveThe Outbox on Harvey's dashboard→ only what you said yes to
- 7Send and replyYour Gmail mailbox, under your daily cap→ replies drafted toward your calendar link, back in the Outbox
Harvey wakes up every 15 minutes, does the most important job (replies first, then sending, writing and finding), and goes back to sleep. A reply from anyone at a company stops the sequence to everyone there.
Words you'll see
- Signal: one fact Harvey can collect about a business, like “running Google ads” or “no online booking.” It collects nothing until you confirm which ones.
- Cohort: a list built from signals, like “has an agency AND runs Google ads.”
- Outbox: where every drafted email waits for your approve, edit or reject.
- Sending domain: a second domain just for cold email, so your main one never lands in spam.
- Warmup: a service that sends and opens normal mail from a new mailbox for a few weeks so inboxes learn to trust it.
- SPF, DKIM, DMARC: three records on your domain that prove the mail is really from you. Without all three, Gmail junks you.
- Virtual environment: a private copy of Python just for Harvey, so it doesn't mess with anything else on your computer.
Set up a mailbox that won't land in spam
This is the part everybody wants to skip, and it's the part that decides whether anybody ever sees your email. Harvey's own docs say it plainly: sending cold email from your main domain, or at volume on day one, lands you in spam permanently.
Buy a separate domain for cold email
A close cousin of your real name, never your main domain. Harvey's example is
getacme.comnext toacme.com. Any domain registrar works; prices vary by name.Make a Google Workspace mailbox on it
Whereworkspace.google.comHarvey recommends Gmail through Google Workspace for under 50 cold emails a day. Starter is $7.00 per user a month before tax on Google's pricing page (checked 2026-10-31). Microsoft 365 works too; Harvey's
docs/microsoft365.mdcovers it.Add SPF
WhereYour domain host's DNS pageAdd a TXT record with the host
@and this value (Google's record for a domain that only sends through Google Workspace):v=spf1 include:_spf.google.com ~allAdd DKIM
WhereGoogle Admin console: Menu > Apps > Google Workspace > Gmail > Authenticate emailPick your sending domain, click Generate New Record (2048-bit if your host allows it), then Generate. Copy the host name (it looks like
google._domainkey) and the TXT value into a new TXT record at your domain host. Don't click Start authentication until that record is saved. Then go back and click it. Google says a brand-new mailbox may need 24 to 72 hours before it can make the key, and up to 48 hours after that to start working.Add DMARC
WhereYour domain host's DNS pageA TXT record at
_dmarc(that's_dmarc.yourdomain.com). Google recommends starting withp=none, which only reports, and tightening it later.v=DMARC1; p=none; rua=mailto:<a mailbox you actually read>Start warmup, and leave it running
Harvey says 2 to 4 weeks of warmup before real volume, and keep it on after. It recommends TrulyInbox: the Free plan covers one mailbox, and Harvey can read your warmup progress through TrulyInbox's API, which starts on Starter ($29 a month billed monthly, or $264 a year, checked 2026-10-31). Using another warmup service is fine; run
harvey trulyinbox otherlater and it stops asking. Write down the day warmup started.PermissionsA warmup service signs in to your sending mailbox to send and open warmup mail. That's why it's a separate mailbox on a separate domain.
Install Harvey
Get Python 3.11 or newer
Check with
python3 --version. Macs ship 3.9, which won't run Harvey. With Homebrew, Harvey's docs say install 3.13; without Homebrew, use the installer from python.org.brew install python@3.13 python3.13 --versionInstall Claude Code and log in
Skip this if
claude --versionalready prints a version. Claude Code needs a paid plan (Pro, Max, Team or Enterprise); the free plan doesn't include it. Runclaudeonce and follow the browser login.curl -fsSL https://claude.ai/install.sh | bash # open a NEW terminal window, then: claude --versionDownload Harvey and install it
Note
python3.13, notpython3: on a Mac the plain one is the old 3.9. On Linux, plainpython3is fine if it says 3.11 or newer. You'll runsource .venv/bin/activateevery time you open a new terminal for Harvey.git clone https://github.com/ethanplusai/harvey.git cd harvey python3.13 -m venv .venv && source .venv/bin/activate && pip install -e . harvey --help
Connect the mailbox and the email checker
Make a Google Cloud project with the Gmail API on
Whereconsole.cloud.google.com, signed in as your sending mailboxCreate a new project and turn on the Gmail API for it. Google's “Enable Google Workspace APIs” help page shows where, if you get lost.
Set up the sign-in screen as Internal
WhereMenu > Google Auth platform > Branding (click Get Started if you see it)Give it a name (only you see it) and a support email, then under Audience pick Internal, add a contact email and finish. Internal is offered because your mailbox is on Google Workspace, and it matters: Google's docs say a project set to External while in testing gets a login that expires in 7 days.
Create the OAuth client
WhereMenu > Google Auth platform > Clients > Create ClientApplication type Desktop app, any name, then Create. Copy the client ID and the client secret.
PermissionsThe client ID and secret are what let Harvey ask for access to this one mailbox. Treat the secret like a password: it goes in.envand nowhere else.Put the keys in .env yourself
Make your own copy of the settings file, open it, and paste the values after the equals signs. Harvey's
.envis already set to never be uploaded to GitHub.cp .env.example .env open -e .envSign in and test
The first command opens a Google sign-in in your browser. Sign in as the sending mailbox and allow it.
harvey gmail auth harvey gmail testPermissionsHarvey asks to send and read mail in this mailbox, because it sends your approved emails and reads the replies. That's the reason it's a separate mailbox.Get a free email checker key
Wherereoon.comHarvey works out each company's email pattern and checks one address instead of guessing six. Without a checker key, every address stays a “guess” and Harvey never sends to it. Reoon's free plan checks 20 a day (about 600 a month) plus 100 credits at sign-up (checked 2026-10-31). Paste the key into
.envasREOON_API_KEY. ZeroBounce works too, and Harvey sends Microsoft 365 and Google Workspace catch-all domains to it if you add both.
GMAIL_CLIENT_IDYour Desktop app OAuth client's ID
Where: Google Cloud: Google Auth platform > ClientsGMAIL_CLIENT_SECRETThat client's secret
Where: Same place, shown when you create itREOON_API_KEYThe email checker (one checker key is enough)
Where: reoon.com, after sign-upZEROBOUNCE_API_KEYOptional second checker, good for catch-all domains
Where: zerobounce.netTRULYINBOX_API_KEYOptional: lets harvey warmup read your warmup progress
Where: Filled in for you by harvey trulyinbox connectTeach it what you sell and who to email
Train Harvey on your website
Harvey reads your site and writes what it learned into
harvey.local.yaml(your private settings file; it wins over the template and never goes to GitHub), plus a product knowledge file inskills/. It guesses your sender name and email from your domain, so you'll fix those next.harvey train https://your-company.comCheck the settings that matter
Open
harvey.local.yamland check these, line by line. The industries and city below are an Example (made up): put in who you actually sell to. Cities need the state and the country.persona: name: "<your real name>" email: "<your sending address>" product: offer: goal: "book_call" booking_method: "calendar_link" booking_url: "<your calendar link>" meeting_duration: "15 minutes" icp: industries: ["Property Management", "Restaurant"] # Example (made up) titles: ["Owner", "Property Manager"] geography: ["Tampa, FL, United States"] channels: email: provider: "gmail" max_daily_sends: 20 require_approval: true warmup: start_date: "<the day your warmup started, YYYY-MM-DD>" compliance: postal_address: "<a mailing address you get mail at>" do_not_contact: - "<a customer's or competitor's domain>"Permissionsrequire_approval: trueis the line that keeps every email in the Outbox until you say yes. Leave it on.Confirm what it looks for
Harvey knows how to collect 29 signals about a business and collects none of them until you say so. Look at the list, then turn on the free ones (26 of them). Paid ones like search rank need their own yes later.
harvey signals harvey signals --confirm free
First test: a small batch and its drafts (free, sends nothing)
This costs no money: the default lead source is free, reading websites is free, and the writing uses your Claude plan. With approval on, nothing goes out.
harvey discover --estimate --city "Tampa, FL"
harvey discover --city "Tampa, FL" --limit 20
harvey warmupThe estimate should say $0 on OpenStreetMap, and --limit 20 caps each search at 20 results. Then open two terminal windows in the Harvey folder (run source .venv/bin/activate in each). In the first, start the dashboard and open the private link it prints. In the second, start Harvey.
harvey dashboardharvey runGive it a few cycles, then open the Outbox. Each draft sits next to what Harvey knew when it wrote it: the company, how the address was found and checked, and the signals the email uses. Read five. Don't approve any of them yet.
Good: under 75 words, a first line about something you can confirm on their site in ten seconds, one plain ask, the opt-out line and your mailing address underneath. Bad: “I came across your company,” a fact you can't find on their site, or a pitch with a price in the first email. Reject those with R and fix the writing rules (the prompts under “Real use” below).
Stop Harvey with Ctrl+C when you're done looking.
Going live: approve the first emails by hand
Wait for READY
harvey warmupchecks SPF, DKIM, DMARC, the domain's age, blocklists and your warmup, and ends with READY or NOT READY. Withwarmup.start_dateset, Harvey sends no cold email for 14 days, then starts at 5 a day and adds 3 a day up to your cap. Replies always go out.Approve one email at a time
WhereDashboard > OutboxJandKmove,Eedits,Aapproves,Rrejects. Approved emails go out on schedule, under your daily cap. To send only in each recipient’s office hours, remove the # marks in front ofsend_windowin your settings file. I'd read every one for the first couple of weeks. You're the sender, it's your name on it.Know where the brake is
This stops all outgoing email right away and leaves everything else as it is.
harvey sending resumeturns it back on.harvey sending pause
Real use: prompts for real jobs
Harvey's sales know-how lives in plain text files in skills/. Change a file and the next cycle writes differently, no restart. Run these in Claude Code inside the Harvey folder.
Run harvey outbox and read the drafts waiting there. Tell me in plain words what makes them sound pushy or generic. Then suggest edits to skills/email_frameworks.md that fix it. Show me the change and wait for my yes before you save it. Don't approve or reject anything in the Outbox.When people say <the objection you hear most>, here's what I actually say back: <your answer>. Add that to skills/objection_handling.md in the same style as the rest of the file. Show me the change and wait for my yes.Add these to compliance.do_not_contact in harvey.local.yaml, one per line: <your customers' and competitors' domains>. Show me the change before you save it.Run harvey status and harvey warmup. Tell me in five lines: what went out, how many replies, any bounces, whether the domain is still READY, and what's waiting on me. Don't approve, send or change anything.What it costs
| Piece | Plan | List price |
|---|---|---|
| Harvey | Open source (MIT) | $0 |
| Claude Code | Claude Pro (Max starts at $100 a month) | $20 a month billed monthly, or $200 a year up front |
| Sending mailbox | Google Workspace Starter | $7.00 per user a month, before tax |
| Sending domain | Any registrar | Varies by name |
| Warmup | TrulyInbox Free (1 mailbox) or Starter (adds the API Harvey reads) | $0, or $29 a month billed monthly ($264 a year) |
| Email checker | Reoon free plan | $0 for 20 checks a day |
| Finding businesses | OpenStreetMap (the default) | $0 |
| Smallest setup | Claude Pro + Workspace, free warmup and checker | $27 a month + the domain |
The plan's limits are the real budget. Harvey runs on your Claude plan's usage, not a per-email bill, and it throttles itself: by default it stops at 80% of your quota so there's room left for your own Claude work (usage.max_daily_claude_percent in the settings file). harvey usage shows where you are. Paid lead sources are the only thing that bills per use, and they always estimate first.
When it breaks
command not found: harvey
source .venv/bin/activate in the Harvey folder first. Every new terminal window needs it.SyntaxError or odd import errors right after install (Mac)
rm -rf .venv && python3.13 -m venv .venv && source .venv/bin/activate && pip install -e .ModuleNotFoundError: No module named 'harvey' (Mac)
harvey install again; it fixes a Mac quirk that hides the package from Python 3.13.Claude calls fail, or the log says the Claude CLI “lacks --safe-mode”
claude update, and claude once to make sure you're logged in on a paid plan. harvey status --check checks it without using a prompt.Discovery finds nothing
harvey signals --confirm free): nothing is collected until you do. On the free source, your trade may just be thin there; see harvey discover --providers.It found people but never sends to them
REOON_API_KEY (or ZeroBounce) to .env.The Gmail connection dies after about a week
harvey gmail auth again.The dashboard says “locked”
harvey dashboard printed, or print it again with harvey dashboard --url. Use 127.0.0.1 or localhost, not another name.Emails land in spam
harvey warmup, fix any missing SPF, DKIM or DMARC record, make sure warmup is still running, and halve your daily cap.A warning about the postal address
compliance.postal_address in harvey.local.yaml. US law wants a mailing address you actually get mail at.Harvey does nothing during the day
harvey status shows the current state.“Overpass is throttling”
You need it to stop right now
Ctrl+C in the window running harvey run, or harvey sending pause to stop outgoing email and leave the rest running. Everything is saved, so it picks up cleanly.That's the setup
Cold email still works when it does the homework first: a real reason in the first line, a checked address, and your eyes on every email before it goes.
Checked on Oct 31, 2026 against
Every claim about a third-party tool in this guide (plans, prices, menu paths, commands, limits) was checked against these official pages on Oct 31, 2026. These screens change often: if something looks different, trust the page over this guide.
- Harvey on GitHubWhat it does, the MIT license, the subscription model, the signals, the pipeline, the sub-agents, the dashboard, troubleshooting, and calendar booking on the roadmap.
- Harvey: Quick startPython 3.11+, the install commands,
harvey train,signals --confirm free,discover,dashboard,run. - Harvey: You confirm what it looks for29 signals, 26 free, nothing collected until confirmed; the cohort builder.
- Harvey: Nothing sends without youApproval by default, the Outbox keys, the pre-send gate, autopilot and what it still holds, the kill switch.
- Harvey: Legal and deliverabilityCAN-SPAM defaults, do-not-contact, bot disclosure, a dedicated domain, SPF/DKIM/DMARC, 2 to 4 weeks of warmup, the ramp.
- Harvey: .env.exampleThe Gmail OAuth client (Desktop app),
harvey gmail auth, and why a checker key is needed (without one, addresses stay “guess” and are never sent). - Harvey: harvey.yamlEvery setting in this guide: persona, offer and booking link, ICP, approval, daily cap, warmup ramp, postal address, do-not-contact.
- Harvey: CLAUDE.mdThe built-in setup wizard for Claude Code.
- Claude Code: Advanced setupThe install command,
claude --version, and which plans include Claude Code. - Claude: Plans and pricingPro at $20 a month billed monthly or $200 a year up front; Max from $100 a month (checked 2026-10-31).
- Google Workspace: PricingStarter at $7.00 per user a month before tax (checked 2026-10-31).
- Google Workspace: Set up SPFThe SPF record for a domain that only sends through Google Workspace.
- Google Workspace: Set up DKIMAuthenticate email, Generate New Record, the TXT record, Start authentication, and the wait times.
- Google Workspace: Set up DMARCThe
_dmarcrecord and starting withp=none. - Google for Developers: Configure OAuth consentGoogle Auth platform > Branding, Get Started, and the Audience step.
- Google for Developers: Create access credentialsGoogle Auth platform > Clients > Create Client, application type Desktop app.
- Google for Developers: Using OAuth 2.0An External project in testing gets a refresh token that expires in 7 days.
- TrulyInbox: PricingFree for 1 account; Starter $29 a month billed monthly or $264 a year, with API access (checked 2026-10-31).
- Reoon Email VerifierFree plan: 20 checks a day (about 600 a month) plus 100 credits at sign-up (checked 2026-10-31).
- FTC: CAN-SPAM Act compliance guidePenalties up to $53,088 per email; the requirements, including your postal address and honoring opt-outs.
