Every agent-driven email workflow bottoms out in a contact database. The agent needs to know who to email, what context to include, and what happened last time. That data layer — the B2B marketing database — is the part most teams underinvest in, and it shows up as broken threads, stale contacts, and agents reasoning over garbage data.
This guide covers how to design a contact database that actually supports agent email workflows. Not the CRM abstraction layer, but the underlying schema, enrichment pipelines, verification loops, and API integration patterns that make agent-driven email reliable at B2B scale.
Why your contact database matters for agent email
A human marketer can glance at a CRM record, notice the phone number looks wrong, and skip that contact. An agent cannot. It reads the data, trusts the data, and acts on the data. If your B2B marketing database has stale email addresses, the agent sends to them. If the job title is two years old, the agent references it in personalized copy. If the company was acquired six months ago, the agent emails the old domain.
The quality of your contact database directly determines the quality of your agent's email output. This is not a nice-to-have — it is the single largest factor in whether your agent email system works or embarrasses you.
Three things distinguish a B2B contact database built for agents from one built for human-driven workflows:
- Structured verification state — every email address carries a verification status and last-verified timestamp, not just a boolean "valid" flag
- Event-driven enrichment — inbound email replies update contact records automatically, not on a manual review cycle
- Agent-readable schema — fields are typed and normalized so an agent can query and filter without parsing free-text notes
Schema design for agent-driven B2B databases
A B2B database marketing workflow starts with schema. If the schema is wrong, everything downstream — enrichment, verification, agent queries — compounds the error.
Core contact record
At minimum, an agent-ready contact record needs:
{
"contact_id": "cnt_abc123",
"email": "jane@acme.com",
"email_status": "verified",
"email_verified_at": "2026-07-15T10:00:00Z",
"first_name": "Jane",
"last_name": "Chen",
"job_title": "VP Engineering",
"company": {
"name": "Acme Corp",
"domain": "acme.com",
"industry": "SaaS",
"employee_count_range": "50-200",
"last_enriched_at": "2026-07-10T08:00:00Z"
},
"interaction_history": {
"last_emailed_at": "2026-07-12T14:30:00Z",
"last_replied_at": "2026-07-13T09:15:00Z",
"total_sends": 3,
"total_replies": 1,
"thread_ids": ["thread_xyz789"]
},
"tags": ["active-conversation", "decision-maker"],
"created_at": "2026-06-01T00:00:00Z",
"updated_at": "2026-07-13T09:15:00Z"
}
Notice what is not here: no free-text "notes" field. Agents reason poorly over unstructured notes. Everything an agent needs to decide whether and how to email this contact is in typed, queryable fields.
Email verification state machine
A boolean is_valid field is insufficient. Email addresses move through states, and your agent needs to know which state each address is in:
unknown → pending_verification → verified → bounced
↓
catch_all (risky)
↓
undeliverable
The email_status field drives agent behavior:
- verified: safe to send
- catch_all: the domain accepts all addresses — delivery works, but the person may not exist. Agent should send but flag for monitoring.
- pending_verification: don't send yet — a verification request is in-flight
- bounced: do not send. If a hard bounce, mark permanently and never retry.
- undeliverable: catch-all that bounced, or address that failed SMTP verification
Storing email_verified_at separately lets you implement re-verification policies. An address verified 90 days ago is less reliable than one verified yesterday — your agent should know the difference.
Company-level deduplication
B2B contacts cluster by company. Your database needs a company entity with a stable identifier (domain is the most reliable) so that:
- The agent can reason about "I'm already in a conversation with someone at Acme" before emailing a second contact at the same domain
- Enrichment data (company size, industry, funding) is stored once and updated centrally
- Thread-level context spans contacts within the same organization
Without company deduplication, agents treat jane@acme.com and tom@acme.com as unrelated — and may send conflicting messages to two people at the same company in the same week.
Enrichment via inbound email parsing
The most valuable enrichment data for a B2B marketing database comes from actual email conversations, not third-party data providers. When a contact replies to your agent, the reply itself contains signal:
- Email signature: job title, phone number, LinkedIn URL, office address — often more current than any database
- Reply content: mentions of team size, projects, timelines, budget constraints
- Headers:
X-MailerandUser-Agentreveal email client;Receivedheaders reveal infrastructure
An inbound email parsing pipeline can extract this automatically. When the agent receives a reply through a webhook, a pre-processing step parses the signature block and updates the contact record before the agent sees the message.
Signature extraction pipeline
inbound webhook → strip reply chain → extract signature block
↓
parse: name, title, phone, social URLs
↓
compare with existing contact record
↓
update if newer (confidence threshold)
The confidence threshold matters. A signature that says "Jane Chen, CTO" when your database says "Jane Chen, VP Engineering" is likely a real promotion — update it. A signature that says "Best regards, J" tells you nothing — skip it.
This creates a self-enriching database: every email conversation makes your contact records more accurate, without paying for third-party enrichment APIs on every record.
Bounce-driven database hygiene
Hard bounces are free verification signals. When your agent sends to jane@acme.com and gets a 550 bounce, that is a confirmed-invalid address. Your inbound email classification layer detects bounces before the agent processes them, and the bounce handler should:
- Set
email_statustobouncedwith a timestamp - Increment a bounce counter on the company record
- If >50% of addresses at a domain bounce, flag the domain for review (possible acquisition, shutdown, or domain change)
- Remove the contact from any active agent workflows
Agents that keep sending to bounced addresses destroy sender reputation. Automate this — never rely on manual database cleanup.
Verification loops for B2B contact databases
Static database snapshots decay. People change jobs, companies get acquired, and email addresses go stale. A B2B contact database needs continuous verification to remain useful for agent email workflows.
SMTP-level verification
Before your agent sends to a new or stale address, verify it at the SMTP level:
- DNS lookup: confirm the domain has MX records
- SMTP handshake: connect to the MX, issue
EHLO,MAIL FROM, andRCPT TO - Interpret the response: 250 = valid, 550 = invalid, 252/450 = uncertain (catch-all or greylisting)
This verification runs asynchronously — queue it when a contact enters the database and re-run on a schedule (every 30–90 days depending on your volume and risk tolerance).
Reply-based implicit verification
The strongest verification signal is a reply. If jane@acme.com replied to your agent's email last week, that address is verified — no SMTP check needed. Update email_verified_at on every inbound reply.
This creates a natural verification tier:
- Reply-verified (last 30 days): highest confidence, send freely
- SMTP-verified (last 90 days): good confidence, send with normal monitoring
- Stale (>90 days, no SMTP check): re-verify before sending
- Unknown: verify before first send
Your agent should respect these tiers. An agent that blasts unverified addresses will tank your domain reputation in days.
API integration patterns
Your agent needs to query the contact database at multiple points in its workflow. The API layer between the agent and the database should support these core operations:
Contact lookup before send
Before sending any email, the agent queries the database:
GET /contacts?email=jane@acme.com
Response:
{
"contact_id": "cnt_abc123",
"email_status": "verified",
"last_emailed_at": "2026-07-12T14:30:00Z",
"active_threads": 1,
"company_contacts_in_conversation": 2
}
The agent uses this to decide:
- Is the address safe to send to? (email_status)
- Am I already in a conversation with this person? (active_threads)
- Is another agent already talking to someone at this company? (company_contacts_in_conversation)
Post-send event capture
After every send and every inbound reply, the database records the event:
POST /contacts/cnt_abc123/events
{
"type": "email_sent" | "reply_received" | "bounce" | "ooo_detected",
"thread_id": "thread_xyz789",
"timestamp": "2026-07-15T10:30:00Z",
"metadata": { ... }
}
This event log drives the interaction history that agents use for personalization and timing decisions.
Batch operations for database maintenance
Verification, enrichment, and cleanup run as batch jobs against the full database:
POST /contacts/batch/verify
{
"filter": { "email_verified_before": "2026-04-01" },
"action": "smtp_verify"
}
Queue-based batch operations prevent your verification jobs from overwhelming the SMTP servers you are checking against. Rate-limit to ~10 verifications per second per target domain — faster than that and you will get blocked.
Scaling a B2B contact database for agent workflows
Agent email systems create database access patterns that differ from traditional CRM usage:
- Read-heavy at send time: the agent queries contact + company + interaction history before every email
- Write-heavy on inbound: every reply triggers contact updates, event logging, and potentially company enrichment
- Fan-out on company lookups: "find all contacts at this domain" is a hot query path
For databases under 100K contacts, a well-indexed PostgreSQL table handles this fine. Beyond that, consider:
- Read replicas for agent send-time queries (these can tolerate seconds of lag)
- Write-through cache on company records (frequently read, infrequently written)
- Async enrichment queue so inbound reply processing doesn't block webhook acknowledgment — return 200 to the webhook immediately, then enrich in a background worker
The webhook acknowledgment point is critical. Inbound email webhooks have timeout requirements. If your enrichment logic takes 5 seconds, you will start missing webhooks. Accept the webhook, queue the enrichment, process asynchronously.
Frequently Asked Questions
What is a B2B marketing database?
A B2B marketing database is a structured collection of business contact records — email addresses, job titles, company information, and interaction history — used to drive targeted communication with other businesses. For agent-driven email, this database serves as the data layer that agents query before sending, update after receiving replies, and use to maintain conversation context across contacts and companies.
How do you keep a B2B contact database accurate?
Continuous verification through three channels: SMTP-level email verification on a 30–90 day cycle, implicit verification via inbound reply signals (a reply confirms the address is valid), and bounce-driven cleanup that immediately flags hard-bounced addresses. Enrichment from email signature parsing on inbound replies keeps job titles and contact details current without manual review.
Should B2B contact data live in a CRM or a separate database?
For agent email workflows, a separate operational database is preferred. CRMs are designed for human workflows — they store unstructured notes, lack verification state fields, and their APIs are not optimized for the high-frequency read/write patterns agents produce. Use a purpose-built contact database for agent operations and sync summary data back to the CRM for human visibility.
How does email verification affect agent sending reputation?
Directly. Sending to unverified or bounced addresses increases your hard bounce rate, which ISPs use as a primary spam signal. An agent that sends 100 emails with a 10% bounce rate will trigger reputation damage within days. Verify before sending, remove bounces immediately, and separate verified from unverified contacts in your database so agents never accidentally send to the wrong tier.
How many contacts can an agent email system handle?
The bottleneck is not contact count — it is the query and update patterns. A well-indexed PostgreSQL database handles 100K–500K contacts for agent workflows without issues. Beyond that, add read replicas for send-time lookups and async processing for inbound enrichment. The real scaling challenge is verification: re-verifying 1M addresses every 90 days means ~11K verifications per day, which requires careful rate limiting against target mail servers.