Any business system that sends email—password resets from a customer portal, invoice notifications from a CRM, status updates from an internal workflow—will eventually encounter bounces and complaints. A bounce means the receiving mail server rejected or could not deliver your message. A complaint means a recipient marked your email as spam rather than unsubscribing or deleting it. Both signals feed back into your application and, if ignored, erode your sender reputation to the point where legitimate messages stop arriving.
Bounces come in two categories. A hard bounce indicates a permanent problem: the mailbox does not exist, the domain does not accept mail, or the address is syntactically invalid. A soft bounce reflects a temporary condition: the recipient's inbox is full, the receiving server is temporarily unavailable, or a rate limit has been triggered. The distinction matters because hard bounces require immediate suppression, whereas soft bounces may warrant a retry after a delay.
Complaints arrive through feedback loops. When a recipient clicks "mark as spam" in their email client, some mailbox providers (notably those running Abuse Reporting Format feedback loops) send a notification back to the sending service. Your email provider—whether that is a cloud service like Amazon SES, SendGrid, Mailgun, Postmark, or your own SMTP infrastructure—typically exposes these events through webhooks or an API. The critical point for a business application is that this data must flow back into your system, not sit unprocessed in a log.
Sender reputation operates at the domain and IP level. If your application repeatedly sends to addresses that hard-bounce, or generates complaints above a threshold, mailbox providers begin throttling or rejecting your mail. The exact thresholds vary by provider and change over time, so treating any specific figure as a safe limit is unwise. Instead, the operational principle is straightforward: every bounce and complaint should be recorded, every hard-bounced address should be suppressed from future sends, and complaint rates should be monitored as a system health metric rather than an afterthought.
Processing bounce webhooks
Most transactional email providers push event data to a webhook endpoint your application exposes. The payload typically includes the recipient address, the bounce type, a diagnostic code, and a timestamp. Your application needs to parse this payload, look up the corresponding user or contact record, and update it. The minimum action for a hard bounce is flagging the email address as undeliverable and preventing any future sends to it from within your system.
For soft bounces, the logic is more nuanced. A single soft bounce might not warrant suppression, but repeated soft bounces from the same address over a short window suggest a persistent problem. A common approach is to increment a counter on the contact record and suppress after a defined number of consecutive soft bounces. The exact number depends on your tolerance for failed delivery attempts versus the risk of suppressing a reachable address. This is a business decision that should be documented and adjustable rather than hardcoded without explanation.
Syncing suppression back to your application
Email sending services maintain their own suppression lists to protect their reputation and yours. However, relying solely on the provider's suppression creates a gap: your application may still attempt to send to a bounced address, consuming API calls, triggering unnecessary logging, and in some cases counting against your sending limits. The application database should mirror the suppression state. When a bounce webhook arrives, update the contact record. When a new user is created or an email address is changed, check it against the existing suppression list before the first send.
Handling complaints in a business-system context
Complaints from transactional emails require immediate investigation. Unlike marketing mail, where a complaint might simply indicate poor targeting, a spam complaint on a password-reset email or an order confirmation suggests something is wrong: the recipient did not expect the email, did not recognise the sender, or could not find a legitimate way to stop receiving it. When a complaint webhook arrives, the application should suppress the address immediately and flag the event for review. The review should check whether the email was genuinely transactional, whether the sender name and address were clearly identifiable, and whether the user had any active account or relationship that would explain the send.
Retry logic and queuing
For soft bounces, retry behaviour needs careful design. Retrying immediately is counterproductive; the receiving server is unlikely to have recovered. Retrying after a fixed delay is simple but does not account for different failure types. A more robust approach uses exponential backoff with a maximum retry count, and stops retrying if the bounce type changes to hard. The retry queue itself should be visible to operations staff so that stuck or accumulating retries can be identified without digging through logs.
Operational monitoring
Bounce and complaint rates are leading indicators of deliverability problems. A sudden spike in hard bounces can indicate a data-quality issue, such as a batch of imported addresses that were not validated. A rise in complaints can indicate a process problem, such as a notification that users find irrelevant but cannot disable. These metrics should appear on the same operational dashboard as system uptime and error rates, not buried in an email provider's separate reporting interface.
Treating all bounces identically
Applying the same logic to hard and soft bounces is a frequent error. Suppressing on every soft bounce will eventually block reachable addresses during temporary outages at major mailbox providers. Conversely, retrying hard bounces wastes resources and signals to receiving servers that your application does not respect permanent failure responses. The webhook payload includes a bounce classification for a reason; the application logic should use it.
Not maintaining an application-level suppression list
When the suppression list lives only inside the email provider, your application loses visibility. Staff cannot see which addresses are suppressed without logging into a separate system. More importantly, if you ever change sending providers, the suppression data does not transfer automatically. The application database should be the authoritative record of whether an address is deliverable, with the sending provider's suppression acting as a safety net, not the primary mechanism.
Ignoring diagnostic codes
Bounce payloads include SMTP-enhanced status codes that explain the rejection reason. A 550 code with "mailbox not found" is unambiguous. A 421 code with "too many connections" points to a rate-limiting issue on your side, not a problem with the recipient address. Logging and, where appropriate, acting on these codes allows you to distinguish between address-level failures and infrastructure-level problems that affect all sends.
Not testing webhook handling
Webhook endpoints can fail silently. If your application returns a non-200 response, most providers will retry, but if the endpoint is misconfigured or the parsing logic throws an unhandled exception, bounces and complaints will accumulate without being processed. During development and after each deployment, verify that the webhook endpoint is reachable, that it correctly parses the provider's current payload format (providers do change these), and that the resulting database updates actually occur.
Confusing transactional complaints with marketing complaints
A complaint on a marketing email is a targeting or frequency problem. A complaint on a transactional email is a deeper issue: either the recipient does not recognise your organisation, or the email looks like marketing despite being system-generated. The response should differ. For transactional complaints, review the email's from name, subject line, and content to ensure it is clearly identifiable as a service message from your organisation, not a promotional send.
Key checks before going live
- Confirm the webhook endpoint is registered with your sending provider and returning successful responses.
- Verify that hard bounces result in immediate suppression in your application database.
- Confirm that soft bounces increment a counter and suppress after the defined threshold.
- Check that complaint events suppress the address and create a review flag.
- Ensure suppressed addresses are excluded from all outbound email queries, not just the specific workflow that triggered the original bounce.
- Confirm that bounce and complaint rates are surfaced in your operational monitoring, not only in the email provider's dashboard.
- Verify that changing or re-adding an email address on a contact record checks the suppression state before allowing future sends.
Handling bounces and complaints is not a one-time configuration. Sending providers update their webhook formats, mailbox providers adjust their feedback-loop policies, and your own application's email patterns change as new features are added. Periodically reviewing the bounce-handling logic, the suppression rules, and the monitoring setup prevents a gradual drift into deliverability problems that are expensive and slow to reverse.