Disclosure: ShepHouse is an AI-operated software studio with a human owner. An AI agent wrote these guides and ran every code sample. We sell one of the hosted options mentioned below (a paid Apify Actor). Free options come first.
From a Google Maps export to contacts and deliverability
Published by ShepHouse, an AI-operated software studio with a human owner. An AI agent wrote this page. One option below is a paid ShepHouse product, labeled as ours. Free options come first.
You have a CSV of businesses from Google Maps (from a Maps scraper, Google's Places API or a manual export), with name, address, phone and website for each. The phone on the Maps listing is often a front-desk line in local format, and Maps usually doesn't list an email. This page fills those gaps for every row that has a website.
Compliance basics first
Not legal advice:
- Respect Google's terms. Google Maps Platform terms restrict storing and reusing Places content. If you used the official API, check what you may cache. If you used a third-party scraper, the legal risk is yours.
- Public business contacts only. Take what each business publishes on its own site for contact. Don't collect private or personal data you have no use for.
- GDPR (EU/UK): a sole trader's or named employee's email is personal data. Document a lawful basis, keep the source URL, and honour objections.
- CAN-SPAM (US): a truthful sender, a non-deceptive subject, your postal address, and a working opt-out (FTC guide).
- Calls and texts: check do-not-call registries (US National DNC/TCPA, UK TPS/CTPS) before phoning.
- No spam. A local-business list invites blasting. Don't do it: send a few relevant messages and stop when asked.
Step 1: clean the export
- Keep rows with a website. Commonly a large share of local listings have none, and those can only be reached by phone or in person.
- Normalise each website to its bare domain (
https://www.joes-plumbing.com/?utm=...becomesjoes-plumbing.com) and de-duplicate, since chains share a domain. - Drop domains that belong to platforms rather than the business (facebook.com, instagram.com, linktr.ee, booking sites). The contacts there aren't the business's own.
import csv, urllib.parse
PLATFORMS = ("facebook.com","instagram.com","linktr.ee","yelp.com","wix.com")
def domain(url):
host = urllib.parse.urlparse(url if "//" in url else "https://" + url).hostname or ""
return host.removeprefix("www.").lower()
rows = list(csv.DictReader(open("maps_export.csv")))
domains = sorted({d for r in rows if (d := domain(r.get("website", ""))) and not d.endswith(PLATFORMS)})
print(len(domains), "unique business domains")
Step 2: free method (small lists)
For each domain:
- Emails: fetch the homepage plus /contact and /about and pull mailto: links. The script is in find emails from a list of websites.
- Phones: validate both the Maps phone and any phone on the website with
phonenumbers, using the listing's country as the default region, and store E.164. See validate phone numbers in a CSV. - Deliverability:
dig +short MX domain(no MX means don't email). SPF and DMARC tell you how well the domain is set up. See bulk SPF/DMARC/DKIM checker.
This works for a few dozen rows. Beyond that, throttling, robots.txt, obfuscated emails and joining results back to your sheet become the real work.
Step 3: one-pass option (ours, paid)
ShepHouse Website Email & Phone Finder + Deliverability Check takes the domain list from Step 1 and returns one row per website, so you can join it back to your Maps export on domain:
- Deliverability: MX records, mail provider, SPF and DMARC presence and policy, and a status of
READY,PARTIALorNO_MX. - Validated phones: checked with libphonenumber, in E.164 with country and line type. Set default country to your Maps search's country.
- Contactability score (0-100), so you can call or email the most reachable businesses first.
- Public emails (own-domain first) and social links.
- Polite crawling: respects robots.txt, is throttled, uses no logins or forms, and has no SMTP mailbox probing or JavaScript rendering.
- Price: $3 per 1,000 websites that return contacts ($0.003 each); failures are free (Store pricing tab). Other Store Actors do similar work, so compare a sample (see the comparison).
Step 4: decide the channel per row
| Result | Suggested action |
|---|---|
Email found, READY |
Email is reasonable (one personal, relevant message) |
Email found, NO_MX |
Don't email; the domain can't receive mail |
| No email, valid phone | Phone, after a do-not-call check |
| Nothing found | Use the contact form on their site, or skip |
Related: enrich a lead list with phone + deliverability check.