Monthly HubSpot email hygiene sweep with NeverBounce

On the first of each month, bulk-verify your stale HubSpot contact emails, stamp the results back on every record, and post a domain reputation summary in Slack.

Agentic Task
HubSpotNeverBounceSlackSalesMarketingData SyncLead Enrichment
PromptCreate

Build me a monthly HubSpot email hygiene sweep. Trigger: cron, first day of every month at 6am in my local timezone. Use HubSpot, NeverBounce, and Slack.

Step 1. Pull stale contacts from HubSpot. Use HubSpot Search Contacts to find every contact whose custom email_verification_status property is empty OR whose email_verification_checked_at (or lastmodifieddate on that property, whichever exists) is older than six months. Page through results until you have the full set. Collect the email addresses in a single list along with each contact's HubSpot record id so we can update them later. Skip contacts with no email.

Step 2. Submit ONE bulk job to NeverBounce. Call Create Bulk Verification Job with the full list as a supplied input, auto_parse and auto_start enabled, and a job name like "hubspot-hygiene-YYYY-MM". This is important: do NOT loop and create small jobs. NeverBounce rate-limits at roughly ten jobs per 100k emails per hour and will disable API access if we abuse it. One large monthly batch is the recommended "Hygiene Loop" pattern.

Step 3. Poll Get Bulk Job Status on that job id until job_status is complete. Back off sensibly (start around 30 seconds, then 60, then a few minutes) so we don't spam the API. If the job goes into under_review, keep waiting up to one business day before giving up.

Step 4. Walk Retrieve Bulk Job Results, paginated. For each row, match the email back to its HubSpot contact id and call HubSpot Update Contact to set email_verification_status to the NeverBounce result code (valid, invalid, disposable, catchall, or unknown) and set email_verification_checked_at to today. When the result is invalid OR disposable, also set the built-in lead status property (hs_lead_status) to "Disqualified" so those contacts stop syncing into active Marketing Hub campaigns. Batch the updates with HubSpot Batch Update Contacts (up to 100 per call) to stay within API limits.

Step 5. Post a summary to Slack. Use Slack Send a Message to a marketing-ops channel (let me pick the channel when I set up the workflow). Include: total contacts checked, a tally per result code (valid / invalid / disposable / catchall / unknown), the count of contacts auto-disqualified this run, and an estimated Marketing Hub savings figure calculated as (auto-disqualified count) times my per-contact Marketing Hub cost, which I will supply as a config value (default $0.05 per contact per month if I don't set one).

Guardrails. Never delete a HubSpot contact. Never touch contacts outside the stale-window filter. If NeverBounce returns throttle_triggered, back off and retry. If the job fails or has zero results, still send a Slack message so I know the sweep ran. Log the NeverBounce job id in the Slack summary so I can dig in if something looks off.

Additional information

What does this prompt do?
  • Finds every HubSpot contact whose email has not been verified in the last six months and sends them all to NeverBounce as a single bulk job
  • Stamps the verification result (valid, invalid, disposable, catch-all, or unknown) back onto each contact on a custom property
  • Auto-sets lead status to Disqualified for anyone flagged as invalid or disposable so they stop draining Marketing Hub seat cost and hurting your sender reputation
  • Posts a monthly domain reputation report to a Slack channel with totals, a tally per result code, and an estimated Marketing Hub savings figure
What do I need to use this?
  • A HubSpot account with a custom contact property for storing the verification result (for example, email_verification_status)
  • A NeverBounce account with enough credits to cover the contacts you want to sweep
  • A Slack workspace and the channel where the monthly hygiene report should land
How can I customize it?
  • Change the schedule if once a month is too little or too much (weekly for aggressive hygiene, quarterly if your list is small and stable)
  • Adjust the staleness window (six months by default) or add filters like lifecycle stage, list membership, or lead source to scope the sweep
  • Point the summary at a different Slack channel, add teammates in the recap, or extend the message with your own domain reputation metrics

Frequently asked questions

Will this delete contacts from HubSpot?
No. Contacts are never deleted. We only stamp the verification result on the contact and set lead status to Disqualified when an email is unsendable. You can reverse either change at any time.
What does Disqualified actually change in HubSpot?
It sets the built-in lead status field so those contacts stop syncing into your active Marketing Hub campaigns. That is usually where domain-hurting sends and Marketing Hub seat cost come from.
How many NeverBounce credits will this use?
One credit per contact verified. Because the workflow only re-checks contacts whose email has not been verified in the last six months, ongoing monthly runs cost far less than the first sweep.
Can I run it weekly or quarterly instead?
Yes. Change the schedule when you set up the workflow. Weekly makes sense for large, actively-growing lists, and quarterly is fine for small stable ones.
Why one big bulk job instead of checking contacts one at a time?
NeverBounce rate-limits accounts that create many small jobs and can pause API access if it looks abusive. Submitting one large monthly batch is the pattern NeverBounce recommends and keeps you well inside the limits.

Stop paying Marketing Hub for dead email addresses.

Connect HubSpot, NeverBounce, and Slack once, and Geni cleans your CRM on the first of every month.