Salesforce Email Verification: Apex, Flow, and Data Loader Integration Patterns for 2026

Salesforce holds the single largest concentration of B2B contact data in most organizations, which makes verification inside Salesforce disproportionately important for overall deliverability. This guide covers the four practical patterns (Apex callout, Flow HTTP, Data Loader, Batch Apex), the exact code and Flow configuration for each, and the governor limit rules that decide which pattern fits which volume tier.

100
Callouts per Apex transaction (Salesforce hard limit). This single number determines which verification pattern you can use at which volume tier. Cross it and the transaction fails. Design around it and everything works.
Quick Answer

How to Add Email Verification to Salesforce

Choose the pattern that fits the scenario. For real-time verification on new Lead or Contact records, use an Apex trigger with a future or Queueable callout to the verification API. For no-code verification (admin-buildable, no developer required), use a Flow with an HTTP Callout action introduced in Winter 24. For one-time bulk cleanup of the existing database, export via Data Loader, verify externally, and re-import with matched Ids. For ongoing scheduled re-verification, use Batch Apex on a nightly or weekly cron. Governor limits (100 callouts per transaction, 60-second execution window, 10MB heap) determine which pattern fits at which volume: real-time patterns handle up to about 100K new records per month per org, bulk patterns handle any volume as one-time operations, and Batch Apex handles ongoing re-verification of 10K to 500K records per run.

Why Salesforce Verification Is Different

Salesforce is not just another CRM. It sits at the center of most B2B revenue operations, which means the contact data inside Salesforce flows outward to marketing automation, sales sequencing, ABM platforms, customer success tools, and the ESP itself. A bad address inside Salesforce becomes a bad address across the entire go-to-market stack, and it stays there indefinitely because Salesforce is treated as the source of truth.

The verification problem is also unusual because Salesforce has strict runtime limits. You cannot naively loop through 100,000 Leads and call an external API for each one from a trigger; the transaction fails on the callout limit. Every practical Salesforce verification pattern is shaped around these constraints, which is why the four patterns below exist as distinct approaches rather than variations on one theme.

🔧
Data Gravity
Salesforce is usually the source of truth. A bad address in Salesforce becomes a bad address in every downstream system.
🔐
Runtime Constraints
Governor limits (100 callouts per transaction, 60 seconds, 10MB heap) shape every pattern. Design around them, not against them.
🔍
Multiple Entry Points
Web-to-Lead, Marketing Cloud sync, Data Loader imports, integrations. Each entry point needs its own verification hook.
📈
Decay Over Time
Even verified addresses go stale as contacts change jobs. Ongoing re-verification is not optional at scale.

The Four Patterns and When to Use Each

The right pattern depends on when the verification needs to happen and how many records are involved. Most mature Salesforce orgs run more than one in parallel: real-time on new Leads, Batch Apex on quarterly re-verification, and Data Loader for one-time cleanup when the org onboards a new list.

1
apex_callout
Real-time on Lead or Contact insert. Handles up to 100K new records per month per org. Requires developer.
2
flow_http
Same real-time pattern but no code. Admin-buildable via Flow HTTP Callout. Works for the same volume tier.
3
data_loader
Bulk export, external verification, bulk re-import. Handles any volume as a one-time operation. No governor limits.
4
batch_apex
Scheduled periodic re-verification. Handles 10K to 500K records per run. Runs nightly or weekly.

Pattern 1: Apex Callout on Lead Insert

The most direct pattern is a Lead trigger that fires a callout to the verification API when a new Lead is created. Because triggers cannot make synchronous HTTP callouts from a DML transaction, the pattern uses a Queueable (or @future method) to defer the callout to a separate transaction. The Lead is created immediately; the verification result populates a moment later.

The endpoint the trigger calls is the standard real-time email verification API, which returns results in about 400ms per call. That timing matters for the callout budget math later in this guide.

The complete trigger and callout class:

LeadVerificationTrigger.trigger
trigger LeadVerificationTrigger on Lead (after insert) {
    Set<Id> leadIds = new Set<Id>();
    for (Lead l : Trigger.new) {
        // Skip if no email or already verified via upstream integration
        if (String.isNotBlank(l.Email) && l.BEC_Verified_At__c == null) {
            leadIds.add(l.Id);
        }
    }

    if (!leadIds.isEmpty()) {
        // Defer to Queueable so we can do HTTP callouts safely
        System.enqueueJob(new BECVerifyLeadsQueueable(leadIds));
    }
}
BECVerifyLeadsQueueable.cls
public class BECVerifyLeadsQueueable implements Queueable, Database.AllowsCallouts {

    private final Set<Id> leadIds;

    public BECVerifyLeadsQueueable(Set<Id> leadIds) {
        this.leadIds = leadIds;
    }

    public void execute(QueueableContext ctx) {
        List<Lead> leads = [SELECT Id, Email FROM Lead WHERE Id IN: leadIds];
        List<Lead> toUpdate = new List<Lead>();

        for (Lead l : leads) {
            HttpRequest req = new HttpRequest();
            req.setEndpoint('callout:BEC_API/real-time/?email=' + EncodingUtil.urlEncode(l.Email, 'UTF-8'));
            req.setMethod('GET');
            req.setTimeout(10000);

            try {
                HttpResponse res = new Http().send(req);
                if (res.getStatusCode() == 200) {
                    Map<String, Object> body =
                        (Map<String, Object>) JSON.deserializeUntyped(res.getBody());

                    l.BEC_Status__c = (String) body.get('status');
                    l.BEC_Is_Disposable__c = (Boolean) body.get('isDisposable');
                    l.BEC_Is_Role_Account__c = (Boolean) body.get('isRoleAccount');
                    l.BEC_Verified_At__c = Datetime.now();
                    toUpdate.add(l);
                }
            } catch (Exception e) {
                System.debug(LoggingLevel.ERROR, 'BEC verify failed: ' + e.getMessage());
            }
        }

        if (!toUpdate.isEmpty()) {
            update toUpdate;
        }
    }
}

The pattern relies on three custom fields on Lead (BEC_Status__c, BEC_Is_Disposable__c, BEC_Is_Role_Account__c, BEC_Verified_At__c) plus one Named Credential (BEC_API) that stores the API key and endpoint. Named Credentials are covered later in this guide because they change how the security posture of the entire integration works. Full response field details are in the email verification API documentation.

Warning: A single Queueable job is limited to 100 callouts. If a bulk Lead insert brings in more than 100 records at once (Web-to-Lead surge, large integration sync, Data Loader import that fires triggers), the Queueable will fail on the 101st callout. The production-safe version of this pattern chains Queueables: process 90 records, enqueue another Queueable for the next 90, repeat until all records are verified.

Pattern 2: Flow HTTP Callout (No Code)

Salesforce introduced HTTP Callout as a Flow action in Winter 24, which means admins can now build verification integrations without writing a single line of Apex. The pattern is functionally equivalent to the trigger + Queueable above but sits entirely inside Flow Builder.

The setup takes 30 minutes for an admin who has built a Flow before:

1
Register the External Service
Go to Setup, Named Credentials, and create an External Credential plus Named Credential pointing to api.bulkemailchecker.com. The permission set that runs the Flow needs access to this credential.
2
Create a Record-Triggered Flow on Lead
In Flow Builder, create a Record-Triggered Flow on Lead, After Save. Trigger condition: Email is not blank AND BEC_Verified_At is null. This ensures verification runs once per Lead when the email is first populated.
3
Add the HTTP Callout Action
Add an HTTP Callout element. Method: GET. Endpoint path: /real-time/. Query parameters: key (from a Custom Metadata Type record) and email (from the triggering record). Sample response: paste in the actual JSON response structure so Flow can auto-generate the output variable schema.
4
Update Lead Fields From Response
Add an Update Records action that writes status, isDisposable, isRoleAccount, and a Verified_At timestamp back to the Lead. Salesforce Flow can reference the parsed response fields directly, so no formula gymnastics required.
The Flow HTTP pattern moves verification from developer land to admin land. RevOps teams that used to wait quarters for engineering bandwidth can now ship verification the same day they need it.
💡
Pro Tip: Flow HTTP callouts hit the same governor limits as Apex callouts (100 per transaction). If your Lead insert volume can exceed 100 in a single DML operation, use a Flow entry criteria that queues via Platform Events or a nightly Batch pattern instead of firing on every insert. The Flow HTTP pattern shines for steady-state signup flows, not bulk import spikes.

Pattern 3: Data Loader Bulk Cleanup

When the goal is to clean an existing database (not verify new records as they arrive), Data Loader is the right tool. This pattern completely sidesteps governor limits because the verification happens outside Salesforce; only the final field updates go through Salesforce APIs.

The workflow: export Contact and Lead Ids plus Email addresses via Data Loader, run the exported CSV through the bulk email verifier, download the enriched results file, and use Data Loader Update with matched Ids to write the verification data back. A million-row Contact table cleans in a few hours end-to-end.

Before running the full export, spot-check a handful of specific addresses through the quick email verifier to confirm the field mappings you plan to update match the response fields being returned. This 30-second sanity check prevents Data Loader Update mistakes at scale.

TRYING TO DO IT IN APEX
  • Governor limit walls: 100 callouts per transaction blocks the whole approach at any real volume
  • Chained Queueables: requires careful queue management to avoid orphaned jobs
  • Slow: 100 Leads per Queueable, 10 second timeout, 500K Leads takes days
  • Complex error handling: partial failures leave the org in inconsistent states
DATA LOADER PATTERN
  • No callout limits: verification happens outside Salesforce, no governor exposure
  • Predictable timing: 500K addresses verify in about 30-60 minutes
  • Simple rollback: bad update? Data Loader Update with the pre-verification snapshot
  • Cost-transparent: exact verification count known before you start
📈
Key Stat: A one-time bulk cleanup of a 500,000-record Salesforce Contact table costs approximately $500 through pay-as-you-go email verification credits at $0.001 per verification, and completes in 30-60 minutes. Equivalent Apex-based verification would take days of chained Queueables and expose the org to callout limit failures.

Pattern 4: Scheduled Batch Apex

Batch Apex is the pattern for ongoing periodic re-verification. Salesforce splits Batch Apex into scopes of 1-200 records; each scope runs as its own transaction with its own governor limits. This means a Batch job can verify tens of thousands of records overnight without hitting the 100-callout-per-transaction limit.

The Batch class implements Database.AllowsCallouts, iterates through Contacts whose BEC_Verified_At is older than 90 days, and re-verifies each. Batch size should be set to 90 (below the 100 callout limit) rather than the default 200. A weekly schedule at 2 am handles most orgs; nightly for high-decay lists.

Field Mapping and Custom Objects

The verification response has more fields than most orgs want to add to Lead and Contact. The pragmatic pattern: add four fields to Lead and Contact (Status, Is_Disposable, Is_Role_Account, Verified_At), and if you need historical verification data, create a Verification_History custom object with a Master-Detail to Lead or Contact.

The four-field minimum:

BEC_Status__c (Picklist)
Values: passed, failed, unknown. This is the single most-queried field. Reports filter on it; validation rules block sends to failed contacts; sales sequences skip unknowns until re-verified. Make it a picklist for report friendliness.
BEC_Is_Disposable__c (Checkbox)
Boolean flag for disposable email services. Marketing typically excludes these from paid ad follow-up but keeps them in the CRM. Sales teams filter reports by this flag to identify tire-kickers. For deeper investigation, use the domain verification tool to check specific domains flagged by the API against MX and reputation data.
BEC_Is_Role_Account__c (Checkbox)
Boolean for role addresses (info@, sales@, support@). These are technically valid but rarely represent individual decision-makers. Useful for B2B routing rules and account-based marketing scoring.
BEC_Verified_At__c (Datetime)
Timestamp of last verification. Batch Apex uses this to identify records due for re-verification. Reports use it to age list segments by freshness. Older than 90 days? Route to re-verification queue.

Governor Limits That Actually Matter

Every integration pattern above is shaped by three specific limits. Ignore them at your own risk.

100 callouts per Apex transaction
The hardest limit. Triggers, Queueables, and Batch Apex scopes each get their own 100-callout budget. A Batch scope of 90 records means each scope makes at most 90 callouts, leaving headroom for other integrations that might also run in the same transaction.
120 seconds total callout time per transaction
All callouts in one transaction combined cannot exceed 120 seconds. At around 400ms per verification, this caps a Queueable at about 250 callouts even if the 100-callout limit did not exist. Set per-callout timeouts to 10 seconds (setTimeout(10000)) to prevent single slow calls from consuming the whole budget.
10 MB heap size per transaction
Large JSON payloads add up. Deserialize the verification response into typed objects rather than keeping full response strings in memory. For orgs verifying at scale, split large record collections into smaller Queueable chains to keep heap usage predictable.

Named Credentials for API Key Security

Hardcoding the API key in Apex classes or Custom Settings is a security anti-pattern. Named Credentials store the key encrypted at the org level and inject it automatically into the callout URL, which means the key is never visible in code, debug logs, or metadata deployments.

The setup: create an External Credential with Custom authentication protocol, add a Named Principal with the API key in a header or query parameter, and create a Named Credential pointing to https://api.bulkemailchecker.com. The Apex code references it as callout:BEC_API without ever seeing the actual key.

Warning: Custom Metadata Types and Custom Settings both expose their values to users with View Setup permission. Storing an API key in either one means every admin in your org can read it. Named Credentials with proper permission set restrictions are the only pattern that keeps the key genuinely private. Make the switch before the first integration goes live.

For agencies managing verification across multiple client orgs, Named Credentials also simplify sub-account management. Each client org gets its own Named Credential pointing at the shared verification service, which pairs well with email verification for teams features for centralized credit management.

Frequently Asked Questions

How do I add email verification to Salesforce?
Choose the pattern that fits the scenario. For real-time verification on new Leads or Contacts, use an Apex trigger with a Queueable callout to api.bulkemailchecker.com/real-time/. For no-code verification, use Flow HTTP Callout (Winter 24). For one-time bulk cleanup, use Data Loader export, external verification via the bulk email verifier, and Data Loader Update. For scheduled re-verification, use Batch Apex.
Can I verify emails in Salesforce without Apex code?
Yes. Since Salesforce Winter 24, HTTP Callout is available as a Flow action. Admins can build a Record-Triggered Flow on Lead or Contact that calls the verification API and writes the result back to record fields, all without writing Apex. The Flow HTTP pattern hits the same governor limits as Apex callouts but requires no developer involvement.
How do I clean an existing Salesforce Contact database?
Use Data Loader for anything over about 10,000 records. Export Ids and Emails, run through the bulk verifier externally, and re-import with Data Loader Update. This sidesteps governor limits entirely and completes 500K records in 30-60 minutes. Apex-based cleanup at that scale is impractical due to callout limits and would take days.
What governor limits affect email verification in Salesforce?
Three matter most: 100 callouts per transaction (hard limit that shapes every pattern), 120 seconds total callout time per transaction, and 10 MB heap per transaction. Design Batch Apex scopes at 90 records to stay under the callout limit; set per-callout timeouts at 10 seconds; deserialize responses into typed objects to control heap.
Where should I store the API key in Salesforce?
Named Credentials with permission-set-restricted access. Custom Settings and Custom Metadata Types both expose their values to anyone with View Setup permission, which is too broad for API key security. Named Credentials store the key encrypted at the org level and inject it into the callout URL automatically.
How often should I re-verify Salesforce Contact records?
Email lists decay at about 22 percent per year in general, but B2B contacts turnover is higher because people change jobs. Quarterly re-verification (every 90 days) is the minimum for active B2B programs. Monthly re-verification is safer for high-volume outbound programs. Schedule via Batch Apex on a nightly or weekly cron so the work happens automatically.

The Bottom Line

Salesforce email verification is not one integration; it is four integrations that fit different scenarios. Real-time patterns (Apex or Flow) handle new records as they arrive. Bulk patterns (Data Loader) clean the existing database in one operation. Scheduled patterns (Batch Apex) keep the database clean over time. Mature orgs run more than one in parallel.

The pattern that matters most for most orgs is the Flow HTTP callout because it removes developer dependency from the day-to-day. Once Named Credentials are in place and the Flow is built, the admin team owns the verification workflow permanently. Engineering only gets involved for the initial security setup and any custom logic that Flow cannot express.

Start With a Sandbox Test: Test a single-address verification response on the free email verification tool to see the exact JSON structure, then wire the same call into your Salesforce sandbox using the Flow HTTP pattern. Ship to production once the field mapping is confirmed in the sandbox. Programs at scale should also review the unlimited email verification API plan to remove per-call cost variance from the runtime.
99.7% Accuracy Guarantee

Stop Bouncing. Start Converting.

Millions of emails verified daily. Industry-leading SMTP validation engine.