Tutorialthe whole build, step by step

Harvey AI sales agent: researched cold email on your Claude plan

Set up Harvey, a free tool that finds businesses, reads their sites and drafts cold emails on your Claude plan, with every send waiting for your yes.

By Eric Snyder, founder 14 min readChecked on Oct 31, 2026
Save this guidereceiptsgroup.com/guides/harvey-cold-email
SetupAn afternoon, then 2 to 4 weeks of mailbox warmup before real sending
Running costHarvey is free (MIT). Claude Pro $20 a month billed monthly + Google Workspace Starter $7.00 per user a month before tax (checked 2026-10-31), plus a domain and a warmup service
You needA paid Claude plan, a separate domain and mailbox to send from, Python 3.11 or newer, a calendar link and a mailing address
SendsNothing, until you approve each email in the Outbox (the default)
Works onMac or Linux as written below; Harvey also runs on Windows
In this guide
Start here
  1. Start here: paste this into Claude Code
The manual way
  1. How the pieces connect
  2. Set up a mailbox that won't land in spam
  3. Install Harvey
  4. Connect the mailbox and the email checker
  5. Teach it what you sell and who to email
  6. First test: a small batch and its drafts (free, sends nothing)
  7. Going live: approve the first emails by hand
  8. Real use: prompts for real jobs
  9. What it costs
  10. When it breaks
  11. Sources, checked Oct 31, 2026

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.

Checked on Oct 31, 2026

Start herepart 1

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.

bashDownload Harvey and start Claude in it
git clone https://github.com/ethanplusai/harvey.git
cd harvey
claude
PromptThe setup prompt (copy all of it)
Hi 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.
The manual wayparts 2 to 11

How the pieces connect

This is the manual way: every step and every command. Claude follows it too.

  1. 1
    Findharvey discover (OpenStreetMap by default, free)→ businesses in your cities and industries
  2. 2
    Read their siteHarvey's profiler: three web requests per business, no AI→ facts like their agency, their ads, no online booking, a stale blog
  3. 3
    Pick the fitsThe signals you confirmed + the cohort builder→ a list where you know why each one is on it
  4. 4
    Find who decidesTheir own team and about pages + your email checker→ a checked address, or no email at all
  5. 5
    WriteClaude, on your Claude plan, with Harvey's writing rules→ a 3-email sequence about something real
  6. 6
    You approveThe Outbox on Harvey's dashboard→ only what you said yes to
  7. 7
    Send 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.

  1. Buy a separate domain for cold email

    A close cousin of your real name, never your main domain. Harvey's example is getacme.com next to acme.com. Any domain registrar works; prices vary by name.

  2. Make a Google Workspace mailbox on it

    Whereworkspace.google.com

    Harvey 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.md covers it.

  3. Add SPF

    WhereYour domain host's DNS page

    Add a TXT record with the host @ and this value (Google's record for a domain that only sends through Google Workspace):

    SPF TXT record value
    v=spf1 include:_spf.google.com ~all
  4. Add DKIM

    WhereGoogle Admin console: Menu > Apps > Google Workspace > Gmail > Authenticate email

    Pick 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.

  5. Add DMARC

    WhereYour domain host's DNS page

    A TXT record at _dmarc (that's _dmarc.yourdomain.com). Google recommends starting with p=none, which only reports, and tightening it later.

    DMARC TXT record value
    v=DMARC1; p=none; rua=mailto:<a mailbox you actually read>
  6. 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 other later 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

  1. 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.

    bashMac with Homebrew
    brew install python@3.13
    python3.13 --version
  2. Install Claude Code and log in

    Skip this if claude --version already prints a version. Claude Code needs a paid plan (Pro, Max, Team or Enterprise); the free plan doesn't include it. Run claude once and follow the browser login.

    bashInstall (Mac, Linux, WSL)
    curl -fsSL https://claude.ai/install.sh | bash
    # open a NEW terminal window, then:
    claude --version
  3. Download Harvey and install it

    Note python3.13, not python3: on a Mac the plain one is the old 3.9. On Linux, plain python3 is fine if it says 3.11 or newer. You'll run source .venv/bin/activate every time you open a new terminal for Harvey.

    bashDownload, install, check
    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

  1. Make a Google Cloud project with the Gmail API on

    Whereconsole.cloud.google.com, signed in as your sending mailbox

    Create 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.

  2. 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.

  3. Create the OAuth client

    WhereMenu > Google Auth platform > Clients > Create Client

    Application 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 .env and nowhere else.
  4. 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 .env is already set to never be uploaded to GitHub.

    bashMake .env and open it (Mac; on Linux use nano .env)
    cp .env.example .env
    open -e .env
  5. Sign in and test

    The first command opens a Google sign-in in your browser. Sign in as the sending mailbox and allow it.

    bashConnect Gmail
    harvey gmail auth
    harvey gmail test
    PermissionsHarvey 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.
  6. Get a free email checker key

    Wherereoon.com

    Harvey 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 .env as REOON_API_KEY. ZeroBounce works too, and Harvey sends Microsoft 365 and Google Workspace catch-all domains to it if you add both.

GMAIL_CLIENT_ID

Your Desktop app OAuth client's ID

Where: Google Cloud: Google Auth platform > Clients
GMAIL_CLIENT_SECRET

That client's secret

Where: Same place, shown when you create it
REOON_API_KEY

The email checker (one checker key is enough)

Where: reoon.com, after sign-up
ZEROBOUNCE_API_KEY

Optional second checker, good for catch-all domains

Where: zerobounce.net
TRULYINBOX_API_KEY

Optional: lets harvey warmup read your warmup progress

Where: Filled in for you by harvey trulyinbox connect

Teach it what you sell and who to email

  1. 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 in skills/. It guesses your sender name and email from your domain, so you'll fix those next.

    bashTrain
    harvey train https://your-company.com
  2. Check the settings that matter

    Open harvey.local.yaml and 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.

    harvey.local.yaml: the parts to check
    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: true is the line that keeps every email in the Outbox until you say yes. Leave it on.
  3. 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.

    bashReview, then confirm the free signals
    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.

bashEstimate, then a small batch in one city
harvey discover --estimate --city "Tampa, FL"
harvey discover --city "Tampa, FL" --limit 20
harvey warmup

The 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.

bashWindow 1: the dashboard
harvey dashboard
bashWindow 2: Harvey
harvey run

Give 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

  1. Wait for READY

    harvey warmup checks SPF, DKIM, DMARC, the domain's age, blocklists and your warmup, and ends with READY or NOT READY. With warmup.start_date set, 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.

  2. Approve one email at a time

    WhereDashboard > Outbox

    J and K move, E edits, A approves, R rejects. Approved emails go out on schedule, under your daily cap. To send only in each recipient’s office hours, remove the # marks in front of send_window in your settings file. I'd read every one for the first couple of weeks. You're the sender, it's your name on it.

  3. Know where the brake is

    This stops all outgoing email right away and leaves everything else as it is. harvey sending resume turns it back on.

    bashKill switch
    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.

Prompt1. The drafts sound generic
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.
Prompt2. Teach it how you answer an objection
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.
Prompt3. Keep people off the list
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.
Prompt4. The Monday check
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

Checked 2026-10-31 on each company's pricing page. Prices and intro offers change: check before you buy.
PiecePlanList price
HarveyOpen source (MIT)$0
Claude CodeClaude Pro (Max starts at $100 a month)$20 a month billed monthly, or $200 a year up front
Sending mailboxGoogle Workspace Starter$7.00 per user a month, before tax
Sending domainAny registrarVaries by name
WarmupTrulyInbox Free (1 mailbox) or Starter (adds the API Harvey reads)$0, or $29 a month billed monthly ($264 a year)
Email checkerReoon free plan$0 for 20 checks a day
Finding businessesOpenStreetMap (the default)$0
Smallest setupClaude 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
Run source .venv/bin/activate in the Harvey folder first. Every new terminal window needs it.
SyntaxError or odd import errors right after install (Mac)
Your virtual environment was built with the Mac's old Python 3.9. Rebuild it: rm -rf .venv && python3.13 -m venv .venv && source .venv/bin/activate && pip install -e .
ModuleNotFoundError: No module named 'harvey' (Mac)
Run 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”
Run 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
Confirm signals first (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
No email checker key, so every address is a “guess.” Add REOON_API_KEY (or ZeroBounce) to .env.
The Gmail connection dies after about a week
Your sign-in screen is set to External in testing, and Google expires those logins in 7 days. Set the audience to Internal (Google Auth platform), then run harvey gmail auth again.
The dashboard says “locked”
Open the exact link 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
Almost always the domain, not the writing. Run 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
Set compliance.postal_address in harvey.local.yaml. US law wants a mailing address you actually get mail at.
Harvey does nothing during the day
Check quiet hours and whether it hit its share of your Claude plan. harvey status shows the current state.
“Overpass is throttling”
That's OpenStreetMap's free servers. Wait a few minutes, or use a paid source for bulk work.
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.

Rather skip the setup?

Want help setting this up?

Receipts Group builds these systems. Thirty minutes with Eric tells you which piece is worth building first, or that none of them are. The guides stay free either way.

Keep going

more free guides