Contact Us

May 4, 2026

May 8, 2026 12:49 am

Sync Hard Bounces from SFMC to Salesforce CRM 2026: The Architecture Most Teams Get Wrong

Share with

Sales teams rely on Salesforce CRM to tell them whether a Contact or Lead is reachable. If someone’s email has permanently bounced in SFMC, the CRM record should reflect that — so sales reps are not wasting calls following up on “did you get my email” with someone whose inbox has been dead for months.

The integration is straightforward in concept but has a nuance that catches most teams out when they first build it. Simply querying the _Bounce Data View for hard bounces and syncing everything you find is not the correct approach. The result will be a lot of noise, false flags, and contacts marked as unreachable in CRM who are actually perfectly fine.

The mistake almost everyone makes: Filtering _Bounce WHERE BounceCategory = 'Hard bounce' and treating all results as actionable is wrong. Hard bounces from non-trusted ISPs are handled by SFMC as soft bounces — the subscriber stays Active and continues receiving emails. Only hard bounces from trusted ISPs result in the subscriber being moved to Held status immediately. If you sync every hard bounce event to CRM, you will be flagging contacts in CRM as unreachable when SFMC itself is still happily sending to them.

How SFMC Actually Handles Bounces

Before building the sync, understanding the subscriber status model matters. SFMC does not treat all hard bounces equally, and the path a subscriber takes depends on whether the bounce came from a trusted ISP.

Bounce Source SFMC Treatment Subscriber Status After Should Sync to CRM?
Hard bounce — trusted ISP Immediate suppression Held / Undeliverable Yes — permanent failure confirmed
Hard bounce — non-trusted ISP Treated as soft bounce, retried Bounced (temporary) No — SFMC still sending to this address
3+ bounces in 15 days (any ISP) Automatic suppression after threshold Held Yes — threshold reached, permanently suppressed
Subscriber opens/clicks after bounce Status reset to Active Active No — email was deliverable despite bounce record

The correct signal to sync to CRM is not a bounce event in _Bounce. It is a subscriber reaching Held status in _Subscribers. That is the moment SFMC itself has decided the address is permanently undeliverable and stopped all future sends. That is what your CRM should know about.

The Full Architecture

Hard Bounce to CRM Sync — End-to-End Architecture
Source 6 months of bounce event history. Contains every bounce — hard and soft, trusted and non-trusted ISPs.
📋

Data View
_Bounce
BounceCategory, SubscriberKey, EventDate
JOIN on SubscriberKey
👤

Data View
_Subscribers
Status = ‘Held’ filter
The key join Only Held status confirms SFMC has permanently suppressed the address. This is your CRM-worthy signal.
🔍

Automation Studio
Daily SQL Query Activity
Filters: BounceCategory = ‘Hard bounce’ AND _Subscribers.Status = ‘Held’ AND EventDate last 24h
Run daily at 3 AM Incremental date filter keeps the DE small. Overwrite action. Only confirmed suppressions written.
🗃️

Staging Data Extension
Hard_Bounce_Staging_DE
Sendable · SubscriberKey as PK · EmailAddress · BounceDate
Sendable required Must be sendable with a CRM ContactID / LeadID send relationship for the Journey Object Activity to match records.
🛤️

Journey Builder
Entry: Staging DE · Evaluate All Records · Re-entry Always
Object Activity: Find and Update on Contact and Lead
Re-entry Always A contact can hard bounce multiple times or across different sends. Re-entry ensures the BounceDate is always updated to the most recent event.
☁️

Salesforce CRM
Contact & Lead Records
Hard_Bounce__c = TRUE · Hard_Bounce_Date__c = date
Custom fields Create these on both Contact and Lead. Sales reps and reports can now filter on email reachability instantly.

The SQL Query

This is the exact query for the daily Automation Studio step. It joins _Bounce with _Subscribers to confirm Held status, applies a 24-hour incremental filter, and brings in the email address and bounce category for context in the staging DE:

Automation Studio — Daily Hard Bounce Staging SQL

/* Pulls confirmed hard bounces — only where SFMC has also moved
   the subscriber to Held status. This is the CRM-worthy signal.
   Run daily. Action: Overwrite on Hard_Bounce_Staging_DE. */

SELECT DISTINCT
    b.SubscriberKey,
    b.EmailAddress,
    b.BounceCategory,
    b.SMTPCode,
    LEFT(b.SMTPBounceReason, 500) AS BounceReason,
    b.EventDate                 AS BounceDate

FROM   _Bounce         b
JOIN   _Subscribers    s  ON  b.SubscriberKey = s.SubscriberKey

WHERE
    b.BounceCategory = 'Hard bounce'
    AND s.Status     = 'Held'
    AND b.EventDate >= DATEADD(day, -1, GETDATE())
    AND b.EventDate <  GETDATE()
Note on SMTPBounceReason length: The SMTPBounceReason field in _Bounce is nvarchar(max) — it has no length limit in the data view. When writing to a Data Extension, always wrap it in LEFT(SMTPBounceReason, 500) or similar to stay within the DE field character limit, otherwise the query will fail silently on records with long bounce reason strings.

Setting Up the Salesforce CRM Fields

Before configuring the Journey, create two custom fields on both the Contact and Lead objects in Salesforce CRM. These are simple to set up via Setup in the CRM:

  • Hard_Bounce__c — Checkbox field. Ticked when the Journey Object Activity runs. Sales reps can filter their views on this field immediately.
  • Hard_Bounce_Date__c — Date/DateTime field. Set to the BounceDate value from the staging DE. Gives visibility into when the address became undeliverable.

In the Journey Builder Object Activity, configure it as Find and Update. Match on SubscriberKey to ContactID and LeadID respectively. Map Hard_Bounce__c to true and Hard_Bounce_Date__c to the BounceDate field from the journey DE. Set the Journey to Re-entry Always so that if the same contact bounces again at a later date, the BounceDate in CRM is updated to the most recent event.

Run the Journey from within the Automation: The cleanest setup is to have the Automation Studio automation trigger the Journey after the SQL query completes — not on a separate schedule. If the Journey fires before the SQL populates the DE, it will process zero records for that run. Chain them in the automation: SQL Query Activity first, Journey fires as the final step automatically when you add it as an Automation type entry source.

CRM Fields to Add to Your Page Layouts

Once the fields exist and data starts populating, add them to the Contact and Lead page layouts in Salesforce so sales reps can see email reachability at a glance. A simple section called “Email Deliverability” with the two fields is enough. You can also add a CRM report or list view filtered on Hard_Bounce__c = TRUE so the sales team has a single place to review and action these records periodically.

Setup Checklist

  • Create Hard_Bounce__c (Checkbox) and Hard_Bounce_Date__c (DateTime) on both Contact and Lead objects in Salesforce CRM.
  • Create the staging DE as sendable, with SubscriberKey as the primary key and a send relationship linked to the CRM ContactID or LeadID field.
  • The SQL query must JOIN _Subscribers and filter on s.Status = 'Held'. Filtering on _Bounce alone is not sufficient.
  • Wrap SMTPBounceReason in LEFT(..., 500) to prevent silent query failures on records with long bounce reason strings.
  • Configure the Journey with Re-entry Always so BounceDate stays current if the same address bounces across multiple campaigns.
  • Chain the SQL activity and Journey in the same Automation Studio automation. Do not schedule them independently.
  • After the first run, spot-check five records in CRM to confirm Hard_Bounce__c = TRUE and verify the BounceDate matches the SFMC bounce event.
  • Add a CRM list view or report filtered on Hard_Bounce__c = TRUE so the sales team can action these records without needing to query the data themselves.

Frequently Asked Questions

What if the same subscriber has both a Contact and a Lead in CRM?

The Object Activity in Journey Builder can only target one object type per activity. For orgs where the same SubscriberKey might exist as both a Contact and a Lead (common in pre-conversion pipelines), add two separate Object Activities in the Journey — one targeting Contact, one targeting Lead. The Find logic will return no results and skip cleanly for the object type where the record does not exist, so it is safe to run both.

Should we set HasOptedOutOfEmail on the CRM record instead of a custom field?

We recommend against it for bounce data. HasOptedOutOfEmail represents a deliberate opt-out, not a deliverability failure. Mixing the two signals in one field makes reporting unclear and can cause problems if a subscriber’s email address is updated and the record should become reachable again. Keep bounce data in its own dedicated fields so you can distinguish “this person asked not to be emailed” from “this email address does not work”.

How do we handle it if a bounced address later becomes valid again?

SFMC will reset a subscriber’s status from Held back to Active if they open or click a link in a forwarded version of an email, or if a Salesforce Support case is raised to manually release the Held status. In those cases, you would want to set Hard_Bounce__c = FALSE in CRM. The cleanest way to handle this is a second daily query against _Subscribers for any subscriber where status has returned to Active and Hard_Bounce__c is currently TRUE in CRM, and run a corresponding Journey Object Activity to clear the flag.

Does this work if we use Marketing Cloud Connect versus a custom integration?

Yes, but the mechanics differ slightly. With Marketing Cloud Connect in place, the Journey Object Activity handles the CRM update natively — it uses the MC Connect bridge to write directly to Salesforce objects. If you are using a custom integration without MC Connect, you need to use SSJS with the UpdateSingleSalesforceObject AMPscript function wrapped in TreatAsContent, or export the staging DE via SFTP and have your integration layer pick it up and process the CRM updates.

Genetrix Technology · Salesforce Marketing Cloud Partner

SFMC and Salesforce CRM Not Talking to Each Other Properly?

Bounce data, unsubscribe signals, engagement scores — keeping SFMC and Salesforce CRM in sync requires deliberate architecture. Genetrix designs and implements these integrations for clients who need their CRM to reflect the real state of their email deliverability.

Talk to Genetrix →

Blogs for the

Business-Savvy!​

Let’s Connect

A 30 min no cost strategy session
with cloud support expert

Let’s Connect

A 30 min no cost strategy session
with cloud support expert