Zheat Outbound

    White paper: how we build cold email lists of local businesses from Google Maps (2026)

    RJ

    RJ, Founder, ZheatUpdated

    Executive summary

    Local businesses are hard to reach with cold email. B2B databases like Apollo cover software companies well, but a plumber in Lyon or a dental clinic in Austin is often missing, outdated or tied to the wrong postcode. Google Maps has them all, with the address, phone, website and reviews that the owner keeps up to date because customers use them.

    This white paper describes the stack we run to turn Google Maps into a verified cold email list:

    1. Growth bots search Google Maps by category and postcode and export every matching business.
    2. An AI qualification prompt removes the businesses that don't fit before we spend anything on them.
    3. An owner lookup finds the decision-maker's name from each business's domain.
    4. An email guesser builds the likely addresses from that name and checks them one by one with MillionVerifier, stopping at the first valid one.

    A sequencer runs these stages city by city, and the finished list is uploaded to Instantly or Smartlead. Our cold email specialists manage the mailboxes and keep an eye on every bot.

    The result is a list of owners with addresses that a verifier has confirmed, built for a fraction of what a database export costs, and accurate to the street.

    Who runs it: specialists and bots

    Cold email specialists manage our sending mailboxes: domains, warm-up, placement and replies. The repetitive work is split between bots, each with one job:

    BotJob
    Search botPulls local businesses from Google Maps with its own API key
    Verification botChecks every email before it is sent, and checks that the other bots did their job properly
    SequencerRuns the pipeline step by step, one city at a time
    Reply botSorts incoming replies and drafts an answer tailored to each one

    The specialists review what the bots produce instead of doing it by hand. That is how a small team runs campaigns across dozens of cities.

    The problem with local business data

    Three things make local businesses different from the usual B2B target:

    • They are not in the databases. Contact databases are built from LinkedIn profiles and company websites. A restaurant owner rarely has a LinkedIn profile that says "Owner, Joe's Pizza".
    • Location is the whole targeting. A roofer only works within a radius. A list that is "in the state" instead of "in these postcodes" wastes most of its sends.
    • The email is often personal to the owner. Small businesses use contact@ for customers and the owner's first name for everything else. Guessing the right pattern matters more than in a 500-person company with a fixed format.

    Stage 1: growth bots on Google Maps

    The search bot queries Google Maps with its own API key, through a Maps data API on RapidAPI, so there is no browser automation to maintain. Each search is a category and a location, for example "dentist in 78701".

    The sequencer decides what runs next. It works one city at a time: search every postcode, qualify, find owners, guess and verify emails, then move to the next city. A failed step stops that city only, and each city's list can go live as soon as it is ready instead of waiting for the whole region.

    How we get full coverage:

    • Postcode by postcode. One search returns at most 20 results, so a city-wide search misses most businesses. The bots loop over every postcode in the target area, using a bundled list of 42,734 US postcodes with population, filtered by state, city or minimum population.
    • Deduplication by place ID. Neighbouring postcodes return the same businesses. Every listing has a unique Google place ID, and duplicates are dropped on it.
    • Rate limiting and retries. Two requests per second, with exponential backoff on rate limits and server errors, so a run across a whole state finishes without babysitting.

    Each business comes out as one CSV row:

    FieldUsed for
    Name, address, lat/lngPersonalisation and radius targeting
    WebsiteThe domain the email guesser needs
    PhoneFallback channel, and a sign the listing is active
    Rating, review countQualification and personalisation
    CategoryFiltering out wrong business types

    A business without a website is dropped at this point: no domain, no email to guess.

    Stage 2: qualify before you enrich

    Google Maps will return 10,000 "pizza restaurants in Illinois". Most of them are not your client: chains, franchises, businesses too small or too big for the offer.

    We take a sample of 50 and run them through an AI qualification prompt, 10 at a time. Every time we disagree with a verdict ("that one is a franchise, should be no"), the prompt is corrected. We stop when two rounds in a row need no corrections, then apply the prompt to the whole list.

    This step is not optional. Owner lookup and email finding cost about $0.10 to $0.30 per contact. On 10,000 businesses that is $1,000 to $3,000, and qualifying first removes 50 to 80% of it.

    Stage 3: find the owner

    Google Maps gives you companies, not people. For each qualified domain, a domain-first lookup (we use Blitz) returns the people attached to it, filtered on titles like owner, founder, president or CEO. When the lookup also returns an email, it goes straight to verification. When it returns only a name, the email guesser takes over.

    Stage 4: the email guesser

    The email guesser is a small Python script we keep in our own GitHub repository, with tests for every pattern. It takes a first name, an optional last name and a domain, builds the likely addresses, and asks MillionVerifier about each one in order until one comes back ok. It has no dependencies beyond Python itself and needs only a MillionVerifier API key.

    The order matters. For "John Smith" at company.com, it tries:

    1. john@company.com
    2. john.smith@company.com
    3. johnsmith@company.com
    4. jsmith@company.com
    5. john.s@company.com
    6. j.smith@company.com

    First name alone comes first because that is what most small business owners use. Each check costs one verification credit, so putting the most likely pattern first means most owners are found on the first or second credit, not the sixth.

    Names are cleaned first. Accents and punctuation are removed and everything is lowercased, so "José O'Neil" becomes jose.oneil. A short nickname table adds the common short form next to each pattern: "Michael" is also tried as "Mike", interleaved so mike@ is checked right after michael@, before the longer patterns.

    Only "ok" counts. MillionVerifier answers ok, catch-all, unknown, disposable or invalid. The script stops only on ok. A catch-all domain accepts every address, so a "valid" answer there proves nothing, and sending to guessed addresses on it is how bounce rates climb. Those contacts are set aside rather than sent.

    It fails loudly. An API error, an empty balance or an unexpected response stops the run instead of marking the contact as "not found". A dry-run mode prints the permutations without spending credits, which is how we check the patterns on a new country or naming convention.

    At most six checks per person (ten with a nickname), and usually one or two.

    What the stack produces

    The final spreadsheet has one row per owner: business name, address, category, rating, owner name, verified email and the pattern that matched. It is formatted to the column layout Instantly or Smartlead expects, with the local details as custom fields, and uploaded to the campaign. It sends from separate domains that have been warmed up, as described in our deliverability guide.

    When replies come in, the reply bot sorts them (interested, not now, question, opt-out) and drafts an answer tailored to each one. A specialist checks it before it goes out, and opt-outs are removed right away.

    The local data does the personalisation work. The street, the neighbourhood, the review count or a recent review give you a first line that shows you looked, which is most of what makes cold copy work with strangers.

    Limits

    • Small businesses on Gmail. Some owners use @gmail.com and put that on their listing. The guesser only works on the business's own domain.
    • Catch-all domains. Skipped by design. A share of every list ends up here, more in some sectors than others.
    • Owner data is the weak link. Domain lookup coverage drops for very small businesses. A wrong name produces a wrong email that still fails verification, so the cost is a few credits, not a bounce.
    • Compliance is on the sender. We email businesses about a business offer, honour every opt-out immediately, and follow the rules of the country we send to. In the EU that means a legitimate interest you can explain and an easy way out in every email.

    FAQ

    Is it legal to scrape Google Maps for cold email? The bots use a third-party Maps data API and collect public business listings: name, address, phone, website. Emailing those businesses is regulated by the rules of the recipient's country, such as CAN-SPAM in the US and GDPR in the EU. Send a relevant business offer, identify yourself and honour opt-outs right away.

    Is the whole process automated? The searching, verifying, sequencing and reply drafting are done by bots. Cold email specialists manage the mailboxes, review the bots' work and approve replies before they are sent.

    Why not just buy a list from Apollo or another database? For local businesses, databases have poor coverage and rough locations. Google Maps is complete and accurate to the street, and owners keep their listing up to date because customers use it.

    How does an email permutation finder work? It builds the common address patterns from a person's name and the company domain, such as first name, first.last or first initial plus last name, then checks each one with an email verifier until one is confirmed valid.

    Why does the email guesser stop at the first valid address? Each check costs a verification credit. Stopping at the first ok result, and trying the most common small business patterns first, keeps the cost to one or two credits per person in most cases.

    What happens with catch-all domains? A catch-all domain accepts any address, so the verifier can't confirm one. The script skips them instead of sending to an unconfirmed guess, which keeps the bounce rate low.

    Sources