Google Tag Manager

Forum Discussion

davidh_braze's avatar
davidh_braze
Collaborator
20 days ago

Deliverability Issues?

Hi there,

I have an email campaign that has the following metrics in email performance section:

Unique Recipients: XX,XXX
Sends: XX,XXX (same as above)
Deliveries: 90.79% (XX,XXX)
Bounces: 0.08% (XX)
Spam Reports: 0.01% (X)

The Deliveries tooltip suggests this number and the rate are "sends minus bounces".

However, my bounces are very low. There is certainly a gap of data that's not being accounted for.

Is it likely that the reality is that the Bounce volume being presented is too low and actually there are lots, or could it be that the deliveries volume is higher?

Is there a place in the dashboard where more detailed bounce information is available?

Ideally I'd like to see a breakdown into hard/soft bounces and ideally a breakdown into domains and failure reasons.

Thanks

David

4 Replies

  • Hi davidh_braze​ ,

    Great question - this is a common point of confusion, and you’re right to flag the gap you’re seeing.

    What’s going on with Deliveries vs Bounces

    The Bounce metric shown in the campaign/canvas performance view represents hard bounces only. Soft bounces are not included in that number, which is why:

    • Deliveries = Sends − Hard Bounces
    • Soft bounces can be substantial, but they don’t reduce the Delivery count shown in the UI

    This explains why your hard bounce rate looks very low, while the delivery rate still appears meaningfully lower than 100%.

    How I validated this

    To confirm, I tested this directly using segmentation:

    • I created a segment with:
      • Last received email with tag in last 2 days AND
      • Hard bounced in last 2 days
    • The resulting user count matched the hard bounce count shown on the campaign/canvas metrics exactly.

    I then ran the same test using:

    • Soft bounced more than 0 times in last 2 days AND
    • Last received email with tag in last 2 days 

    That segment was significantly larger and did not match what’s shown in the dashboard — which aligns with soft bounces not being surfaced in campaign-level bounce metrics.

    Where to find more detailed bounce data

    If you’re looking for a deeper breakdown (hard vs soft bounces, domains, failure patterns, etc.), the best place is Analytics → Query Builder, using the shared Snowflake tables.

    Below is an example query that pulls:

    • Hard and soft bounces
    • Sends and deliveries
    • Opens, clicks, unsubscribes, and spam reports
    • broken down by email domain over the last 30 days (you can adjust the date window as needed).

    This should give you the level of visibility you’re looking for, including hard vs soft bounces and domain-level patterns.

    -- Email bounces and sends per domain
    
    WITH hard_bounces AS (
        SELECT email_address,
               RIGHT(email_address, LENGTH(email_address) - charindex('@', email_address)) AS domain
        FROM USERS_MESSAGES_EMAIL_BOUNCE_SHARED
        WHERE date_trunc('day', to_timestamp_ntz(time)) >= dateadd('day', -30, date_trunc('day', CURRENT_DATE()))
    ),
    soft_bounces AS (
        SELECT email_address,
               RIGHT(email_address, LENGTH(email_address) - charindex('@', email_address)) AS domain
        FROM USERS_MESSAGES_EMAIL_SOFTBOUNCE_SHARED
        WHERE date_trunc('day', to_timestamp_ntz(time)) >= dateadd('day', -30, date_trunc('day', CURRENT_DATE()))
    ),
    sends AS (
        SELECT email_address,
               RIGHT(email_address, LENGTH(email_address) - charindex('@', email_address)) AS domain
        FROM USERS_MESSAGES_EMAIL_SEND_SHARED
        WHERE date_trunc('day', to_timestamp_ntz(time)) >= dateadd('day', -30, date_trunc('day', CURRENT_DATE()))
    ),
    delivered AS (
        SELECT email_address,
               RIGHT(email_address, LENGTH(email_address) - charindex('@', email_address)) AS domain
        FROM USERS_MESSAGES_EMAIL_DELIVERY_SHARED
        WHERE date_trunc('day', to_timestamp_ntz(time)) >= dateadd('day', -30, date_trunc('day', CURRENT_DATE()))
    ),
    unique_opens AS (
        SELECT DISTINCT email_address,
               RIGHT(email_address, LENGTH(email_address) - charindex('@', email_address)) AS domain
        FROM USERS_MESSAGES_EMAIL_OPEN_SHARED
        WHERE date_trunc('day', to_timestamp_ntz(time)) >= dateadd('day', -30, date_trunc('day', CURRENT_DATE()))
    ),
    unique_clicks AS (
        SELECT DISTINCT email_address,
               RIGHT(email_address, LENGTH(email_address) - charindex('@', email_address)) AS domain
        FROM USERS_MESSAGES_EMAIL_CLICK_SHARED
        WHERE date_trunc('day', to_timestamp_ntz(time)) >= dateadd('day', -30, date_trunc('day', CURRENT_DATE()))
    ),
    unique_unsubscribes AS (
        SELECT DISTINCT email_address,
               RIGHT(email_address, LENGTH(email_address) - charindex('@', email_address)) AS domain
        FROM USERS_MESSAGES_EMAIL_UNSUBSCRIBE_SHARED
        WHERE date_trunc('day', to_timestamp_ntz(time)) >= dateadd('day', -30, date_trunc('day', CURRENT_DATE()))
    ),
    mark_as_spam AS (
        SELECT DISTINCT email_address,
               RIGHT(email_address, LENGTH(email_address) - charindex('@', email_address)) AS domain
        FROM USERS_MESSAGES_EMAIL_MARKASSPAM_SHARED
        WHERE date_trunc('day', to_timestamp_ntz(time)) >= dateadd('day', -30, date_trunc('day', CURRENT_DATE()))
    ),
    total_bounces AS (
        SELECT * FROM hard_bounces
        UNION ALL
        SELECT * FROM soft_bounces
    ),
    hard_bounce_counts AS (
        SELECT domain, COUNT(*) AS bounces
        FROM hard_bounces
        GROUP BY domain
    ),
    soft_bounce_counts AS (
        SELECT domain, COUNT(*) AS bounces
        FROM soft_bounces
        GROUP BY domain
    ),
    total_bounce_counts AS (
        SELECT domain, COUNT(*) AS bounces
        FROM total_bounces
        GROUP BY domain
    ),
    send_counts AS (
        SELECT domain, COUNT(*) AS sends
        FROM sends
        GROUP BY domain
    ),
    delivered_counts AS (
        SELECT domain, COUNT(*) AS delivered
        FROM delivered
        GROUP BY domain
    ),
    unique_opens_counts AS (
        SELECT domain, COUNT(*) AS unique_opens
        FROM unique_opens
        GROUP BY domain
    ),
    unique_clicks_counts AS (
        SELECT domain, COUNT(*) AS unique_clicks
        FROM unique_clicks
        GROUP BY domain
    ),
    unique_unsubscribes_counts AS (
        SELECT domain, COUNT(*) AS unique_unsubscribes
        FROM unique_unsubscribes
        GROUP BY domain
    ),
    mark_as_spam_counts AS (
        SELECT domain, COUNT(*) AS mark_as_spam
        FROM mark_as_spam
        GROUP BY domain
    )
    
    SELECT total_bounce_counts.domain,
           total_bounce_counts.bounces AS total_bounces,
           COALESCE(hard_bounce_counts.bounces, 0) AS hard_bounces,
           COALESCE(soft_bounce_counts.bounces, 0) AS soft_bounces,
           COALESCE(send_counts.sends, 0) AS sends,
           COALESCE(delivered_counts.delivered, 0) AS delivered,
           COALESCE(unique_opens_counts.unique_opens, 0) AS unique_opens,
           COALESCE(unique_clicks_counts.unique_clicks, 0) AS unique_clicks,
           COALESCE(unique_unsubscribes_counts.unique_unsubscribes, 0) AS unique_unsubscribes,
           COALESCE(mark_as_spam_counts.mark_as_spam, 0) AS mark_as_spam
    FROM total_bounce_counts
    LEFT JOIN hard_bounce_counts ON total_bounce_counts.domain = hard_bounce_counts.domain
    LEFT JOIN soft_bounce_counts ON total_bounce_counts.domain = soft_bounce_counts.domain
    LEFT JOIN send_counts ON total_bounce_counts.domain = send_counts.domain
    LEFT JOIN delivered_counts ON total_bounce_counts.domain = delivered_counts.domain
    LEFT JOIN unique_opens_counts ON total_bounce_counts.domain = unique_opens_counts.domain
    LEFT JOIN unique_clicks_counts ON total_bounce_counts.domain = unique_clicks_counts.domain
    LEFT JOIN unique_unsubscribes_counts ON total_bounce_counts.domain = unique_unsubscribes_counts.domain
    LEFT JOIN mark_as_spam_counts ON total_bounce_counts.domain = mark_as_spam_counts.domain
    WHERE total_bounce_counts.domain IS NOT NULL
    ORDER BY total_bounces DESC
    LIMIT 100;

    Thanks! 
    Hope this helps! 

  • How much time has gone by between sending and this report?  Keep in mind that soft bounces will retry for 72 hours, so the delivery report is not "final" until 3 days after the send.

  • Mari's avatar
    Mari
    Collaborator

    Hi davidh_braze​ , we encountered issues with email deliveries to Microsoft email addresses last week. It may be worth checking whether Microsoft addresses in your database are currently marked as deferred.