Deliverability · 6 min read

Bounce vs complaint: the outbound failure most teams miss

“Sent” is an API response, not a delivery guarantee. The gap between accepted and delivered is where follow-ups, reputation, and revenue quietly leak.

Short answer

A bounce is a rejection by the receiving server. A complaint is a recipient marking an accepted message as spam. Both should suppress the lead and stop future sends, but a complaint should be treated as more severe. A provider “sent” event only means the message was accepted for delivery; it is not proof that the inbox received it.

Most outbound dashboards count a send as soon as the provider accepts the request. That is useful for quota and retries, but it hides the most important question: did the message reach a human?

Four states, not one

StateMeaningWhat to do
AcceptedThe sending provider accepted the requestShow “sent” but keep tracking
DeliveredThe receiving server accepted the messageUpdate delivery; continue the sequence
BouncedThe receiving server rejected the messageSuppress the address, stop the sequence, notify the owner
ComplainedThe recipient marked the message as spamSuppress immediately, treat as critical, review the segment

Bounce: the address is not usable

Hard bounces are permanent: unknown user, invalid domain, blocked recipient. Soft bounces are temporary: mailbox full, server busy, greylisting. For outbound, repeated soft bounces should be treated as unusable because the sequence cannot wait indefinitely.

  • Suppress the address for the workspace, not only the campaign.
  • Stop every queued step for that lead.
  • Keep the send record so the history explains what happened.
  • Notify the owner with the campaign and product context.

Complaint: the message reached the wrong person

A complaint is more serious than a bounce because the message was delivered and rejected by a human. It is a signal that the list, the offer, or the frequency is wrong.

  • Suppress the address immediately.
  • Stop all future steps.
  • Review the segment and the source of the address.
  • Do not “win back” a complainant with another sequence.

The event pipeline that prevents lost bounces

  1. Create the send row before calling the provider, or persist the provider message id before the webhook can arrive.
  2. Verify the webhook signature.
  3. Look up the send by provider message id.
  4. If the send is not ready, return a retryable error instead of acknowledging and losing the event.
  5. Make delivery failure terminal: a later “sent” or “delivered” event must not overwrite a bounce.
  6. Create a notification, suppress the lead, and cancel queued steps in one predictable flow.
The race condition: a webhook can arrive before your send row has the provider message id. If you return 200 ignored, the provider will not retry. The event is gone. Return a retryable status and process it after the row exists.

An email that is accepted but never delivered is not a send. Treat delivery events as part of the product state, not a reporting detail.

FAQ

What is the difference between a bounce and a complaint?

A bounce means the receiving mail server rejected the message. A complaint means the recipient marked an accepted message as spam. Both require suppression, but they describe different failures and should carry different severity.

Does a soft bounce require suppression?

Not always immediately. A temporary soft bounce may clear. A repeated soft bounce or an unknown-user response should be treated as a hard failure for outbound purposes.

Why does my provider say sent when the email bounced?

The provider accepted the message for delivery; that is not the same as the receiving server delivering it. Bounce and complaint events arrive later and must update the send and lead state.

Know when a send actually reached the inbox.

PortKnot tracks delivery events, suppresses bounces and complaints, stops the remaining sequence, and notifies the owner with context.

Start the 7-day trial →