ravn
Claude skill

Clean and enrich a HubSpot contacts export

Take a contacts CSV exported from HubSpot, verify every email, find missing work emails, optionally fill job titles, and produce an import file that updates the existing records. Ravn has no native HubSpot app, so this is a file round-trip: export, enrich with the CLI, re-import.

Download SKILL.md Start free

Install

One command.

Installs into ~/.claude/skills for Claude Code. In Claude, upload the downloaded file under Settings → Capabilities → Skills.

npx ravn skill install hubspot-export-cleanup

When to use

  • Bounces are climbing, or a big sequence is coming up.
  • Contacts have names and companies but no email, or unchecked emails.
  • The user says "clean up my HubSpot contacts" and can export a CSV.

Before you start

  1. Check the connection: npx ravn whoami (free). Note lookups left this window.
  2. reverse_email_lookup needs your own provider key connected — run ravn keys add pdl first; this tool runs on your own provider account. If it returns 403 provider_key_required, stop and tell the human to add their key. Verifying emails and finding emails by name are ours and need no key. Every call is one lookup; misses are free.
  3. Ask the user to export with the Record ID column included. That ID is what lets HubSpot update existing contacts on re-import instead of creating new ones.
  4. Read the header row. Column names vary; common ones are Record ID, First Name, Last Name, Email, Website URL and Job Title. Use the real names.

Steps

  1. Remove opted-out contacts first. Filter out anyone unsubscribed and keep them out of every later step.
  2. Verify existing emails. Quote --map values that contain spaces.
npx ravn enrich contacts.csv --tool validate_email --column Email --dry-run
npx ravn enrich contacts.csv --tool validate_email --column Email --limit 10 --out sample.csv
npx ravn enrich contacts.csv --tool validate_email --column Email --out step1.csv
  1. Split step1.csv locally into: rows with rw_verdict = valid, and rows that are blank, invalid, risky or unknown and have a name plus a company website. Write that second group to needs-email.csv with the step 1 rw_* columns renamed (for example rw_verdict to old_verdict) or dropped, so the next pass does not create clashing column names.
  2. For the second group, try to find a better work email:
npx ravn enrich needs-email.csv --tool search_business_email_by_name --map "first_name=First Name,last_name=Last Name,company=Website URL" --limit 10 --out sample2.csv
npx ravn enrich needs-email.csv --tool search_business_email_by_name --map "first_name=First Name,last_name=Last Name,company=Website URL" --out step2.csv

Accept a found address only when its rw_verdict is valid. Treat risky (catch-all) as a suggestion for the user to review. 5. Optional, needs your provider key: for valid rows with an empty job title, run reverse_email_lookup --column Email on a copy with the step 1 rw_* columns renamed, to fill rw_title, rw_seniority and rw_company. The dry run shows how many lookups the pass will use. 6. Build the import file. Keep Record ID. Write the best email into Email, copy rw_title into Job Title only where it was empty, and add a column such as Email Verdict with the verdict. Never overwrite hand-entered data without asking. 7. Tell the user how to import: Contacts, Import, file from computer, and map Record ID so existing records are updated. Any custom property (like Email Verdict) must exist in HubSpot before it can be mapped.

Output

  • hubspot-import.csv: Record ID plus the updated columns, one row per contact.
  • removed.csv: contacts with no usable email, with rw_verdict and rw_reason.
  • A summary: contacts in, valid as-is, fixed with a new email, titles filled, still unusable, and lookups used.

Working files keep rw_status (ok, not_found, error, dropped), rw_verdict and other rw_<field> columns.

Rules

  • Never re-add or email contacts who unsubscribed or opted out. Ravn's own opt-out page is /privacy#optout.
  • Drop invalid and risky addresses from any sending list.
  • No FCRA uses: do not clean contacts to decide credit, employment, insurance or housing.
  • On a 429 fair_use_exhausted or a 403 provider_key_required, stop and tell the human. Rows not reached are dropped; rerun later to finish.

Example prompt

I exported all 3,200 contacts from HubSpot. Half of them are from an old trade show. Verify the emails, find new ones where they bounced, and give me a file I can import back without duplicates.