Last updated: August 31, 2026

Ben Argeband, Founder & CEO of Heartbeat.ai — Keep it plug-and-play; avoid vendor specifics.
What’s on this page:
Who this is for
This is for recruiting ops leaders who need consistent outreach reporting across an ATS, CRM, dialer, and email tool when recruiting healthcare providers, without turning recruiters into data-entry clerks.
- Recruiting ops building consistent reporting and definitions for physician and clinician outreach
- TA leaders who need channel outcomes that tie back to pipeline stages
- Teams cleaning up suppression, opt-outs, and deliverability before it becomes a brand or compliance issue
Quick Answer
- Core Answer
- Implement a minimum viable ATS field schema that separates contact truth from touch outcomes, so outreach metrics reconcile across email and calling tools when reaching healthcare providers.
- Key Insight
- Reporting breaks when “sent” is treated as “delivered” and opt-outs live in notes instead of contact-level suppression fields.
- Best For
- Recruiting ops building consistent reporting
Compliance & Safety
This method is for legitimate recruiting outreach only. Always respect candidate privacy, opt-out requests, and local data laws. Heartbeat does not provide medical advice or legal counsel.
Framework: separate contact truth from touch outcomes
Store delivery, bounce, and reply events in the email tool. Store call events in the dialer. Store suppression, consent, and verification as contact truth in the ATS/CRM. Then roll up rates using consistent denominators.
Outreach reporting on physician and provider lists fails in predictable ways: tools disagree, recruiters log outcomes differently, and leadership stops trusting the funnel. Standardizing a small set of fields protects deliverability and compliance, makes outcomes comparable across channels, and stays simple enough that recruiters will actually use it.
You’ll lose some nuance that used to live in free-text notes, but you gain metrics that hold up across systems.
Step-by-step method
Step 1: Lock metric definitions with denominators
Lock definitions before you build fields, or your reports will drift by team or tool. Always report the denominator alongside the rate:
- Connect Rate = connected calls / total dials
- Answer Rate = human answers / connected calls
- Deliverability Rate = delivered emails / sent emails
- Bounce Rate = bounced emails / sent emails
- Reply Rate = replies / delivered emails
Delivery and bounce events should come from the email tool. The ATS stores the resulting contact truth (suppression, opt-out, verification dates) so recruiters can’t accidentally re-contact a suppressed provider record.
Step 2: Implement the minimum viable fields first
These are the smallest set of fields that make outreach metrics trustworthy and keep provider outreach out of deliverability trouble:
- Consent: status + source + timestamp
- Opt-out / suppression: status + source + date + scope
- Last verified date: email (and phone if available)
- Last touched date: by channel
- Outcomes by channel: standardized picklists
- Bounce type + bounce reason: hard/soft plus reason taxonomy
- Wrong-person flag: plus corrected-contact workflow
- Suppression source/date: always auditable
For the operational side of this, see suppression lists and opt-out management workflows.
Step 3: Separate contact truth from touch truth
Most teams mix what’s true about a provider contact with what happened on one touch. That mixing causes overwrites and bad suppression decisions. Keep them separate:
- Contact truth (persists): consent, opt-out/suppression, verification dates, wrong-person flag, preferred channel.
- Touch truth (per activity): channel, timestamp, sender identity, template/sequence ID, outcome, bounce taxonomy (email), call disposition (dialer).
Step 4: Create a channel-agnostic Outreach Touch record
If your ATS supports custom objects, build an “Outreach Touch” object. If it doesn’t, simulate one with a structured activity record using required picklists. Either way, keep the fields consistent across the CRM, dialer, and email tool so metrics roll up correctly.
Minimum fields for each touch:
- outreach_touch_id (unique)
- contact_id (ATS contact/candidate ID)
- job_id (if applicable)
- channel (call/email/SMS/other)
- touch_at (timestamp)
- sender_user_id (recruiter)
- sender_mailbox_id or sending_domain (for email)
- outcome (standardized picklist)
- outcome_at (timestamp)
- template_id / sequence_id (if used)
Step 5: Add deliverability protection fields
When bounces spike on a provider outreach campaign, you need to act without guessing. A bounce taxonomy plus a logged action lets ops suppress, verify, refresh, or run authentication checks quickly.
- Classify: bounce_category (hard/soft) + bounce_reason (invalid mailbox, domain not found, blocked/policy, mailbox full, rate limited, other).
- Decide the action and log it: suppression_action_taken = suppress / verify / refresh / auth_check / none.
- Apply suppression as contact truth: opt_out_status + suppression_source + suppression_date + suppression_scope.
Keep a one-page internal “bounce triage decision tree” that starts with bounce_reason and ends with the exact field updates to make in the ATS.
Step 6: Standardize outcomes so “no answer” means the same thing everywhere
Picklists beat free text. Keep the list short enough that recruiters don’t have to guess which option applies.
| Channel | Outcome picklist (copy/paste) | Notes |
|---|---|---|
| Call | no answer; left voicemail; gatekeeper; wrong number; connected (voicemail/IVR); human answered; scheduled follow-up; do-not-call request | When “do-not-call request” occurs, set suppression_scope=phone_only and suppression_source=candidate_request. |
| sent; delivered; bounced-soft; bounced-hard; replied-positive; replied-neutral; replied-negative; auto-reply; unsubscribed/opt-out | Delivery/bounce should be sourced from the email tool event stream. | |
| SMS (if used) | sent; delivered; failed; replied; opt-out | Keep opt-out as contact truth in the ATS. |
Step 7: Assign field ownership so logging actually happens
Recruiters won’t maintain a complex schema by hand. Decide what’s auto-captured versus manually set, and assign an owner to each field group.
| Field group | Where it should be captured | Capture mode | Owner |
|---|---|---|---|
| Delivery events (delivered/bounced + reason) | Email tool | Auto | Ops / systems |
| Suppression status + source/date/scope | ATS contact record | Auto when possible; manual allowed | Ops policy; recruiters execute |
| Call dispositions | Dialer + ATS touch record | Auto from dialer; manual fallback | Recruiters |
| Consent status/source | ATS/CRM contact record | Manual (structured picklist) | Recruiters; audited by ops |
| Verification dates | ATS contact record | Auto from verification workflow | Ops / systems |
Step 8: Choose join keys so your dashboard reconciles
- Primary join: contact_id + outreach_touch_id, when available.
- Fallback join: contact_id + channel + touch_at within a tight time window, treated as a temporary bridge until you add a stable touch ID.
- System-of-record rule: use the email tool for delivered/bounced/replied events, the dialer for dials/connects/answers, and the ATS for suppression/consent/verification and for tying touches to pipeline stages.
This is how you avoid the argument where the ATS says “sent 500” and the email tool says “delivered 430” and nobody trusts either number.
Step 9: Build a copy/paste schema
The appendix below is a vendor-agnostic field map you can hand to ops or your ATS admin. It’s designed to map cleanly across an ATS, CRM, dialer, and email tool.
Diagnostic table
Use this to figure out why outreach metrics don’t reconcile across systems.
| Symptom | Likely root cause | Field(s) missing or inconsistent | Fix (ops action) |
|---|---|---|---|
| Reply Rate looks “too low” in ATS vs email tool | Replies counted against sent instead of delivered | delivered outcome + delivered timestamp; reply outcome + reply timestamp | Store delivered/replied as touch outcomes; report Reply Rate = replies / delivered emails |
| Recruiters keep emailing people who opted out | Opt-out stored in one tool only; no contact-level suppression truth | opt_out_status; suppression_source/date; suppression_scope | Make suppression a required contact field in ATS; block sequences when suppressed |
| Bounce Rate spikes and nobody knows what to do | No bounce taxonomy; no logged action; no owner | bounce_category; bounce_reason; suppression_action_taken | Use the bounce triage ladder; route auth_check to whoever owns sending domains |
| Call metrics don’t predict pipeline movement | Dialer dispositions don’t map to human answers | total_dials; connected_calls; human_answers; call_outcome | Enforce definitions: Connect Rate = connected calls / total dials; Answer Rate = human answers / connected calls |
| Wrong-person contacts keep recycling into campaigns | No wrong-person flag; no corrected-contact workflow | wrong_person_flag; suppression_scope; refresh_task | Set wrong_person_flag=true; suppress that email/phone; create a refresh task |
Keep a short “postmaster checks” checklist for whoever owns sending domains: authentication alignment, reputation signals, and sudden list-quality changes.
Weighted checklist
Score your current schema before you rebuild it. Total 100 points. Under 70, your metrics will be noisy and your deliverability risk is higher than you think.
- (20) Contact-level suppression is explicit (status + source + date + scope)
- (15) Consent/permission is captured (status + source + timestamp)
- (15) Verification is captured (last verified date for email; for phone if available)
- (10) Wrong-person handling exists (flag + suppression + refresh task)
- (10) Touch outcomes are standardized across channels (picklists, not free text)
- (10) Bounce taxonomy exists (hard/soft + reason)
- (10) “Last touched date” is tracked by channel (prevents over-contacting)
- (10) Reporting uses correct denominators (sent vs delivered; dials vs connected)
Nice-to-have: template_id/sequence_id on touches, so you can isolate which messaging correlates with bounces, opt-outs, or replies without reading notes.
Internal ops templates
These are internal templates, not candidate-facing messaging. They reduce back-and-forth and keep logging consistent across the ATS/CRM/dialer/email tool stack.
Template 1: Ops ticket to implement the field map
Subject: Implement ATS outreach metrics field schema (contact + touch)
Body: Add the fields in the attached schema to our ATS and make them available for reporting exports. We need contact-level truth fields (consent, suppression/opt-out, verification dates, wrong-person flag) and touch-level outcome fields (channel outcomes, bounce taxonomy, template/sequence IDs). Deliverables: fields created, picklists configured, required fields enforced on Outreach Touch records, an export/report view, and documentation for auto-captured vs manual fields.
Template 2: Recruiter SOP snippet
When you email: confirm the touch has channel=email and an outcome. Delivery/bounce should be auto-captured from the email tool. On a reply, set outcome=replied-[positive/neutral/negative]. On an opt-out, set opt_out_status=true immediately.
When you call: log the call outcome. If a human answers, mark outcome=human answered, since that drives Answer Rate. If it’s the wrong person, set wrong_person_flag=true and suppress that phone/email.
Template 3: Deliverability incident note
Subject: Bounce spike triage (time window + sending domain/mailbox)
Body: We observed increased bounces. Review the bounce_reason distribution (hard vs soft; invalid mailbox vs blocked/policy). Suppress hard bounces, verify or refresh questionable contacts, and run authentication checks against Postmaster signals. Log suppression_action_taken on the touch and suppression_source/date/scope on the contact.
Common pitfalls
1. Counting “sent” as “delivered”
This inflates denominators and makes Reply Rate look worse than it is. Store sent and delivered separately, and report Reply Rate as replies divided by delivered emails.
2. Opt-outs stored as notes instead of suppression fields
Opt-outs living in notes won’t block future outreach. Make suppression a contact-level truth field with source, date, and scope so it’s auditable and enforceable.
3. Bounce type without bounce reason
Hard vs soft isn’t enough to act on. You need a reason taxonomy to decide whether to suppress, verify, refresh, or run authentication checks.
4. Wrong-person contacts not treated as a data quality event
A wrong-person result should trigger suppression of that specific email or phone number plus a refresh task. Otherwise it keeps recycling back into sequences.
5. Overbuilding fields nobody uses
Start with the minimum viable fields. Add nice-to-have fields only once you see consistent logging behavior.
How to improve results
1. Build a weekly outreach health report
Show rates with denominators, broken out by recruiter and by sending domain or mailbox, not just raw counts.
Email columns:
- sent_emails
- delivered_emails
- bounced_emails
- replies
- Deliverability Rate = delivered_emails / sent_emails
- Bounce Rate = bounced_emails / sent_emails
- Reply Rate = replies / delivered_emails
Call columns:
- total_dials
- connected_calls
- human_answers
- Connect Rate = connected_calls / total_dials
- Answer Rate = human_answers / connected_calls
Pull delivery/bounce/reply events from the email tool, dials/connects/answers from the dialer, and suppression/consent/verification from the ATS contact record. Join on contact_id and outreach_touch_id.
2. Use the bounce triage ladder to protect sending domains
When bounces rise, don’t guess. Classify by bounce_reason, take the logged action, and update contact-level suppression truth so the same bad address doesn’t get hit twice.
3. Tighten verification and refresh cadence
Verification fields stop the argument about whether an address is good and let you act instead: if last_verified_email_at is stale, verify or refresh before sending. If verification isn’t possible, prioritize recently verified contacts and suppress repeated bounces.
Implementation notes
Keep a one-page field map with: field name, object (contact/touch), type, allowed values, whether it’s required, source system, and reporting use.
For deliverability monitoring during incidents, review reputation and error signals in Google Postmaster Tools and align authentication settings as needed.
Legal and ethical use
Outreach data on healthcare providers includes personal contact information and communication preferences. Treat suppression and opt-outs as first-class fields, not optional notes. Honor opt-out requests quickly, avoid contacting suppressed records, and document consent where applicable. If you operate across regions, align your process with local data laws and your organization’s policies.
Evidence and trust notes
We publish how we define and audit outreach metrics so ops teams can compare results across tools. Start here: Heartbeat trust methodology and the deeper definitions page accuracy and metrics definitions.
Deliverability references used in this playbook:
Related internal playbooks:
- Reply rate tracking for physician outreach
- Suppression lists and opt-out management
- How to build a physician call list
FAQs
What are the minimum viable fields I need to report outreach metrics in an ATS?
At minimum: consent status/source/timestamp, opt-out/suppression (status + source + date + scope), last verified date, last touched date by channel, standardized channel outcomes, bounce category + reason, wrong-person flag, and suppression source/date.
Where should bounce data live: ATS or email tool?
The email tool should be the system of record for delivery events (delivered/bounced and bounce reason). The ATS should store the resulting contact truth: suppression status, suppression source/date, suppression scope, and last verified date.
How do I keep call metrics consistent between a dialer and the ATS?
Standardize dispositions and report using fixed definitions: Connect Rate = connected calls / total dials; Answer Rate = human answers / connected calls. Store the call outcome on the touch record and roll up weekly.
What fields prevent repeated outreach to the wrong person?
Add a wrong-person flag at the contact level, suppress the specific email/phone that was wrong, and create a refresh task to find the correct contact. Don’t leave it as a note.
How do I protect deliverability when bounces spike?
Use a bounce taxonomy (hard/soft + reason) and a logged action field (suppress/verify/refresh/auth_check). Review authentication and reputation signals using Postmaster, and stop sending to known-bad addresses.
Next steps
- Implement the minimum viable fields first, then enforce required picklists on Outreach Touch records.
- Standardize reporting using the definitions in accuracy and metrics definitions.
- If you want a workflow that includes ranked mobile numbers by answer probability, start here: create a Heartbeat account.
Appendix: CSV-ready field map (copy/paste)
| Field Name | Object | Type | Allowed Values / Notes | Required? | Primary Source |
|---|---|---|---|---|---|
| consent_status | Contact | Picklist | unknown, implied, explicit, do_not_contact | Yes | ATS/CRM |
| consent_source | Contact | Picklist | candidate_provided, referral, public_profile, prior_relationship, other | Yes | ATS/CRM |
| consent_at | Contact | DateTime | ISO timestamp | No | ATS/CRM |
| opt_out_status | Contact | Boolean | true/false | Yes | ATS (system of record) |
| suppression_source | Contact | Picklist | candidate_request, bounce, internal_compliance, other | Yes | ATS |
| suppression_date | Contact | DateTime | ISO timestamp | Yes | ATS |
| suppression_scope | Contact | Picklist | email_only, phone_only, all_channels, domain_level | Yes | ATS |
| last_verified_email_at | Contact | DateTime | Last time email was verified | Yes | Verification workflow |
| last_verified_phone_at | Contact | DateTime | Last time phone was verified | No | Verification workflow |
| last_touched_email_at | Contact | DateTime | Last email touch timestamp | Yes | Email tool |
| last_touched_call_at | Contact | DateTime | Last call touch timestamp | Yes | Dialer |
| wrong_person_flag | Contact | Boolean | true/false | Yes | ATS/CRM |
| outreach_touch_id | Touch | Text | Unique ID | Yes | ATS/CRM |
| contact_id | Touch | Text | ATS contact/candidate ID | Yes | ATS |
| job_id | Touch | Text | Requisition/job ID (if applicable) | No | ATS |
| channel | Touch | Picklist | call, email, sms, other | Yes | ATS/CRM |
| touch_at | Touch | DateTime | ISO timestamp | Yes | ATS/CRM |
| sender_user_id | Touch | Text | Recruiter user ID | Yes | ATS/CRM |
| sending_domain | Touch | Text | Domain used to send the email (if applicable) | No | Email tool |
| outcome | Touch | Picklist | Use the standardized outcomes table in Step 6 | Yes | ATS/CRM |
| outcome_at | Touch | DateTime | ISO timestamp | No | ATS/CRM |
| bounce_category | Touch | Picklist | hard, soft, none | No | Email tool |
| bounce_reason | Touch | Picklist | invalid_mailbox, domain_not_found, blocked_policy, mailbox_full, rate_limited, other | No | Email tool |
| suppression_action_taken | Touch | Picklist | suppress, verify, refresh, auth_check, none | No | ATS/CRM |
| template_id | Touch | Text | Email template identifier | No | Email tool |
| sequence_id | Touch | Text | Sequence/cadence identifier | No | Email tool |
Note: This page is vendor-agnostic by design and does not assume or claim any native integration between systems.
About the Author
Ben Argeband is the Founder and CEO of Swordfish.ai and Heartbeat.ai. With deep expertise in data and SaaS, he has built two successful platforms trusted by over 50,000 sales and recruitment professionals. Ben’s mission is to help teams find direct contact information for hard-to-reach professionals and decision-makers, providing the shortest route to their next win. Connect with Ben on LinkedIn.