Skip to content

Suppression lists: what to suppress and for how long

Hard bounces, complaints and unsubscribes each deserve different suppression rules. Design a suppression list, scopes and expiry that protect reputation.

Koltrix Team5 min read
A red padlock resting on a black computer keyboard
Photo by FlyD on Unsplash
On this page(8 sections)
  1. Why a suppression list sits below the application
  2. What deserves suppression
  3. Scopes: not every suppression is global
  4. Expiry: how long is long enough
  5. Letting people get un-suppressed
  6. Implementation details that bite
  7. Normalize carefully
  8. Check at send time, not just at enqueue time
  9. Record suppressed sends
  10. Sync with providers
  11. A policy checklist
  12. Key takeaways

A suppression list is the set of addresses your system refuses to email, no matter what the application asks for. Get it wrong in one direction and you keep hammering dead mailboxes and people who complained.

Get it wrong in the other and customers stop receiving password resets because of a bounce from three years ago.

Why a suppression list sits below the application

Application code decides who should get a message: the user who requested a reset, the account owner whose invoice is ready. The suppression list decides who may get one. Keeping that second decision in a single, central layer has three benefits:

  • Every sending path obeys it. API calls, SMTP relay submissions, background jobs and one-off scripts all pass through the same check.
  • Mistakes in application code do not become reputation damage. A bug that tries to email ten thousand bounced addresses is stopped before it reaches a mailbox provider.
  • Compliance is enforceable. Unsubscribe and complaint handling become a property of the platform rather than something each feature must remember.

Most sending services maintain a suppression list for you, and that is a good baseline. If you build your own pipeline, or send through several providers, you need your own list in front of them.

What deserves suppression

Not every negative event means the same thing. Treat them separately.

Event Suppress? Scope Default duration
Hard bounce: mailbox does not exist (5.1.1) Yes All mail to that address Long; months or permanent
Hard bounce: domain does not exist or has null MX Yes All mail to that address Long, with periodic recheck
Spam complaint (feedback loop) Yes Marketing and non-essential mail; often all mail Permanent unless the person opts back in
Unsubscribe Yes The stream or category they left Permanent until they opt back in
Repeated soft bounces over days Sometimes All mail Short; days to weeks
Single soft bounce or deferral No — —
Policy rejection (5.7.x) No, investigate — —

The last row matters. A 5.7.x rejection usually says something about your message or reputation, such as failed authentication, a blocklist hit or content filtering. Suppressing the recipient hides a sender-side problem and does nothing to fix it.

Scopes: not every suppression is global

A single global list is simple and wrong for many products. A person who unsubscribes from your product newsletter still expects a receipt when they pay you. A person who marks a marketing email as spam may still need security alerts.

Model suppressions with a scope:

CREATE TABLE suppressions (
  address      citext       NOT NULL,
  scope        text         NOT NULL,  -- 'all', 'marketing', 'digest', ...
  reason       text         NOT NULL,  -- 'hard_bounce', 'complaint', 'unsubscribe', 'manual'
  source_event text,                   -- message or event id that caused it
  created_at   timestamptz  NOT NULL DEFAULT now(),
  expires_at   timestamptz,            -- NULL means no expiry
  PRIMARY KEY (address, scope)
);

At send time, the check asks: is there an unexpired suppression for this address with scope all, or with the scope of this message's category? Every outgoing message therefore needs a category, which is a useful discipline anyway.

A reasonable mapping:

  • Hard bounces suppress scope all. The mailbox does not exist; no category of mail will get through.
  • Complaints suppress marketing and other optional categories at minimum. Many teams suppress everything except strictly necessary account mail, such as password resets the person explicitly requests.
  • Unsubscribes suppress the specific category or list. Under the Gmail and Yahoo bulk sender rules, one-click unsubscribe requests must be honored within two days, so this write needs to happen promptly, not in a weekly batch.

Expiry: how long is long enough

Permanent suppression of hard bounces sounds safe, but addresses change state. A company domain that lapsed may be reregistered. A mailbox that was disabled may be restored. And an address that bounced because of a temporary misconfiguration on the receiving side was suppressed by mistake.

Practical defaults:

  • Mailbox-does-not-exist bounces: suppress for a long period, such as six to twelve months, then allow one attempt only if the address is actively used again (for example, the user logs in and triggers a message). If it bounces again, suppress for longer.
  • Domain-level failures: recheck DNS after a few weeks; if the domain now has working MX records, allow a retry.
  • Soft-bounce escalations: expire after days or a few weeks.
  • Complaints and unsubscribes: no automatic expiry. Only an explicit opt-in from the person should lift them.

Never automatically lift a complaint suppression just because time has passed. Re-mailing people who reported you is one of the fastest ways to raise your complaint rate.

Letting people get un-suppressed

Users change their minds and fix their mailboxes. Provide paths that do not require a support ticket:

  • When a suppressed user updates their email address, the new address starts clean.
  • When a user explicitly re-subscribes to a category, delete that category's suppression.
  • When an address was suppressed for a hard bounce and the user logs in and asks to resend a verification email, allow a single attempt and show a clear message if it fails again.

Expose suppression status to your support team, with the reason and the event that caused it. "We tried, and the receiving server said that mailbox does not exist on this date" resolves most "I never got the email" tickets in one reply.

Implementation details that bite

Normalize carefully

Domains are case-insensitive. The local part is technically case-sensitive under RFC 5321, but virtually every real mailbox treats it as case-insensitive. Lowercasing the full address for suppression lookups is the pragmatic choice. Do not strip dots or plus tags for suppression purposes; [email protected] may be a deliberately separate address.

Check at send time, not just at enqueue time

A message can wait in a queue while a complaint for that address arrives. Check suppression again immediately before handing the message to SMTP or your provider.

Record suppressed sends

When a message is skipped, record that outcome with the reason, so application developers and support can see "not sent: recipient suppressed (hard bounce)" instead of silence.

Sync with providers

If you send through a provider that maintains its own list, import its suppressions and push yours to it. Divergent lists lead to confusing results, where a message is accepted by your system and silently dropped by the provider.

A policy checklist

  • Suppress hard bounces globally, with a long but finite expiry and a recheck path.
  • Suppress complaints for at least all optional mail, with no automatic expiry.
  • Honor unsubscribes per category within two days.
  • Never suppress on a single soft bounce or on 5.7.x policy rejections.
  • Store scope, reason, source event and expiry for every entry.
  • Check suppression at enqueue and again right before sending.
  • Show suppressed outcomes to developers and support.

Key takeaways

  • The suppression list is a central guardrail that every sending path must pass through.
  • Different events deserve different scopes and durations; one global, permanent list is too blunt.
  • Complaints and unsubscribes are lifted only by explicit opt-in, never by time.
  • Policy rejections point at your sending, not at the recipient, and should be investigated rather than suppressed.
  • Make suppression visible so support can explain missing mail quickly.

Start with Koltrix

Your domain, one inbox, and an API that sends.

A team inbox where AI sorts and drafts (nothing is sent without your click), plus the transactional API and SMTP relay your product sends with. 7 days free, no card.

SharePost on XLinkedIn