skills/compliance/suppression-lists/SKILL.md
Manage email suppression lists. Use when handling bounces, complaints, unsubscribes, DNC lists, GDPR erasure requests, or migrating suppressions between providers.
npx skillsauth add chunkydotdev/email-skills suppression-listsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Manage bounces, complaints, unsubscribes, and do-not-contact records to protect sender reputation and stay legally compliant.
bounce-handling - retry strategies for soft bounces, processing hard bouncesemail-compliance - CAN-SPAM, GDPR, CASL, unsubscribe requirementssender-reputation - how suppressions protect (and repair) your sending reputationwebhook-processing - handling delivery events that trigger suppressionsdomain-authentication - authentication failures that cause delivery issuesA suppression list is a set of email addresses (or domains) that your system will never send to, regardless of whether they appear in a campaign audience or journey. It is the final gate before mail leaves your infrastructure.
Every email platform maintains one, but the important distinction is scope. You need suppressions at multiple levels:
| Scope | What it covers | Example | |-------|---------------|---------| | Global | Addresses suppressed across all tenants/accounts | Known spam traps, legal requests | | Account/tenant | Addresses suppressed for a specific sender | A recipient who complained about your emails | | Campaign | Addresses suppressed for a specific campaign only | Opt-out from a particular newsletter |
Most platforms only give you account-level suppression. That is not enough if you operate multiple brands, send on behalf of customers, or run different mail streams. Build your suppression model with all three scopes from the start.
Not all suppressions are equal. The reason an address was suppressed determines whether it can ever be removed.
The mailbox does not exist or the domain cannot receive mail. The receiving server returned a permanent failure (5xx SMTP status code).
Action: Suppress immediately on first hard bounce. Never retry.
Hard bounces above 0.5% of a send indicate a list quality problem. Providers like Gmail and Microsoft track your hard bounce rate as a sender reputation signal. Above 2%, expect throttling or blocking.
The recipient clicked "Report Spam" or "Mark as Junk" in their mail client. You receive this via feedback loops (FBLs) from providers.
Action: Suppress immediately. A single complaint is a stronger negative signal than a bounce. Gmail's threshold is 0.3% complaint rate, but they recommend staying below 0.1%.
Never email someone who has complained. Not once more. Not to confirm. Not to ask why. Suppression is permanent.
The recipient clicked your unsubscribe link or used the one-click List-Unsubscribe mechanism (RFC 8058).
Action: Suppress within 2 days. CAN-SPAM allows 10 business days, but Google and Yahoo enforce faster processing. Practical standard in 2025+ is immediate or same-day.
Unsubscribe suppressions are scoped. If someone unsubscribes from your newsletter, that does not necessarily suppress them from transactional email (order confirmations, password resets). But if they unsubscribe from "all marketing," respect that globally.
Temporary delivery failures - mailbox full, server temporarily unavailable, message too large. Individual soft bounces are not suppressions; they are retries. But repeated soft bounces to the same address indicate a problem.
Action: After 3 soft bounces within 30 days, suppress with an expiration. A 90-day suppression with automatic expiry is a reasonable default. This protects your reputation while allowing recovery for addresses that come back online.
Retry strategy for individual soft bounces before suppression:
An address added manually by your team - sales prospects who asked not to be contacted, known-bad addresses from list cleaning, addresses flagged during onboarding.
Action: Treat as permanent unless explicitly removed. Document the source and date for audit purposes.
A suppression resulting from a legal demand - GDPR erasure request, CAN-SPAM complaint to the FTC, CASL complaint, cease-and-desist.
Action: Suppress permanently. Never remove. Document the legal basis, jurisdiction, and date. This is the one suppression type where you must retain a record even if the person demands full data deletion (see GDPR section below).
A recipient who has received multiple emails over an extended period with no opens, clicks, or replies. Not a hard signal like a bounce - more a slow fade.
Action: Suppress after a defined inactivity window (typically 90-180 days of no engagement). Consider a re-engagement attempt before suppression (see re-engagement section).
Addresses like info@, postmaster@, abuse@, sales@, support@, webmaster@, admin@, noc@ (see RFC 2142). These go to shared mailboxes or distribution lists, not individuals.
Action: Suppress from marketing and cold outreach. Role accounts generate disproportionate complaint rates because multiple people receive the message and any one of them can report it. They are also common spam trap candidates.
Transactional email to role accounts is fine if the address is a legitimate customer (e.g., [email protected] signed up for your service).
An entire domain suppressed, not just individual addresses. Useful for:
Action: Suppress all addresses *@domain.com. Check both email-level and domain-level suppressions before every send.
At minimum, store these fields for each suppression record:
| Field | Purpose |
|-------|---------|
| recipient_email | The suppressed address (normalized to lowercase) |
| scope | global, tenant, or campaign |
| reason_code | hard_bounce, complaint, manual_dnc, legal_request, soft_bounce, role_account, domain_suppressed, no_engagement |
| source | How the suppression was created: webhook, api, import, manual |
| source_event_id | Link to the originating event (bounce ID, complaint ID) |
| expires_at | Null for permanent, timestamp for temporary (soft bounce) |
| created_at | When the suppression was added |
For domain-level suppressions, maintain a separate table with domain, reason_code, and source.
Suppression checks happen on every single send. This is your hottest path. Design for it:
recipient_email for email-level lookupsdomain for domain-level lookupsexpires_at IS NULL OR expires_at > NOW())A typical query checks: "Is this email (or its domain) suppressed at global, tenant, or campaign scope, and is the suppression currently active?"
When the same address is suppressed again (e.g., a second complaint), update the existing record rather than creating a duplicate. Use an upsert on the natural key of (recipient_email, scope, tenant_id, campaign_id). Update the reason code, source, and event ID to reflect the most recent signal.
The highest-value pattern is fully automated suppression from delivery events. Your system should process provider webhooks and create suppressions without human intervention.
| Webhook event | Suppression action |
|--------------|-------------------|
| bounced (permanent/hard) | Suppress immediately, scope: tenant, reason: hard_bounce |
| bounced (transient/soft) | Track count. After 3 in 30 days, suppress with 90-day expiry |
| complained | Suppress immediately, scope: tenant, reason: complaint |
| Unsubscribe (via List-Unsubscribe POST or link click) | Suppress immediately, scope depends on unsubscribe type |
Provider webhook payloads encode bounce type differently:
bounce.bounceType is Permanent or TransientType is HardBounce or SoftBounce; TypeCode 4000-4099 for soft bouncesWhen the bounce type is ambiguous or missing, treat it as a hard bounce. False positives (suppressing a soft bounce permanently) are far less costly than false negatives (continuing to send to a dead address).
This is the most commonly misunderstood compliance issue in email suppression.
Under GDPR Article 17, a person can request deletion of all their personal data ("right to be forgotten"). But if you delete their email address entirely, you lose the ability to suppress them - meaning they could be re-added to a list and emailed again, violating the very preference they expressed.
GDPR Article 17(3)(b) permits retention of personal data when necessary for "compliance with a legal obligation" or to establish, exercise, or defend legal claims. The ICO (UK), CNIL (France), and EDPB have all acknowledged that maintaining a suppression list is a legitimate basis for retaining the minimal data needed to prevent unwanted contact.
What you can keep:
What you must delete:
When processing a GDPR erasure request:
legal_requestGDPR) to the recordThe 2025 EDPB coordinated enforcement action specifically examined how controllers handle this balance. Controllers who automatically applied the "legal obligation" exception without case-by-case assessment were cited. Document your reasoning for each retention.
When switching email providers, your suppression list is the single most important data export. Missing it causes immediate reputation damage.
Export everything. Pull all hard bounces, complaints, unsubscribes, and manual suppressions from your old provider. Most providers offer CSV export via API or dashboard.
Preserve reason codes. Don't flatten everything into a single "suppressed" list. You need to know why each address was suppressed because different reasons have different re-engagement rules.
Import before your first send. Upload the complete suppression list to your new provider before sending a single message. This is non-negotiable.
Verify the import. Send a test batch and confirm that previously suppressed addresses are blocked. Don't trust the import count alone - spot-check specific addresses.
Maintain the old provider's list. Keep a backup of the exported suppressions. Provider data retention varies and you may lose access after cancellation.
Provider-level suppression lists (their internal blocklists) do not transfer. If Postmark internally suppressed an address based on cross-customer signals, that intelligence stays with Postmark. You only get your own account's suppressions.
This means your first sends from a new provider may hit addresses that were previously blocked by the old provider's shared intelligence. Monitor bounce and complaint rates closely during the first 2-4 weeks after migration.
These suppression types are permanent. Do not attempt re-engagement under any circumstances:
These types may be candidates for careful, limited re-engagement:
If you run a re-engagement campaign for disengaged contacts:
Detecting role accounts requires checking the local part (the portion before the @) against known role patterns.
# RFC 2142 mandated or recommended
postmaster, abuse, hostmaster, webmaster, noc, security
# Business functions
info, sales, marketing, support, billing, admin, contact, office,
help, feedback, hello, general, team, press, media, careers, jobs, hr
# Technical/operations
sysadmin, administrator, root, devops, ops, engineering, it, tech,
dns, ftp, www, mail, smtp, imap
# Catch-all indicators
no-reply, noreply, do-not-reply, mailer-daemon, bounce
Match against the local part, case-insensitive. Some of these (like info@) are extremely common and generate high complaint rates when sent unsolicited marketing. Others (like sales@) might be legitimate contacts in some contexts.
For cold outreach and marketing: suppress all role accounts by default. For transactional email: allow role accounts that are verified customers.
Suppressions tell you who not to email. Consent records tell you who gave permission and on what basis. These are separate concerns but they interact.
| Basis | Description | Example | |-------|-------------|---------| | Explicit opt-in | Person actively chose to receive email | Checked a box, submitted a form | | Legitimate interest | You have a business reason, GDPR Article 6(1)(f) | Existing customer, relevant content | | Contractual | Email is necessary to fulfill a contract | Order confirmations, account notifications | | Legal obligation | Email is legally required | Compliance notices, tax documents |
| Metric | Healthy threshold | Action if exceeded | |--------|------------------|-------------------| | Hard bounce rate | Below 0.5% per send | Pause and clean list | | Spam complaint rate | Below 0.1% (Google's recommendation) | Investigate content and targeting | | Unsubscribe rate | Below 0.5% per send | Review content relevance and frequency | | Suppression list growth rate | Steady or declining | If accelerating, investigate root cause | | Suppression check latency | Under 10ms p99 | Optimize indexes or add caching |
Build these circuit breakers into your send pipeline:
These safeguards prevent a single bad list import or misconfigured campaign from destroying your sender reputation. Tools like molted.email build these circuit breakers into the send pipeline automatically.
This is the number one cause of reputation damage during migration. Your new provider has zero context about who has bounced or complained. You will immediately re-send to dead addresses and angry recipients.
Hard bounces, complaints, and unsubscribes have different severities and different rules for potential removal. A flat "suppressed" flag with no reason code means you cannot make informed decisions later.
Check suppressions at list import time, at campaign audience selection, and at send time. Catching bad addresses early prevents them from inflating your audience counts and distorting campaign metrics.
If you delete the suppression record along with everything else, the address can re-enter your system through a list import or API call and get emailed again. Keep the suppression, delete everything else.
You suppress [email protected] after a hard bounce, but next week [email protected] enters your list and bounces too. Suppress the domain, not just individual addresses, when the domain itself is the problem.
Soft bounce suppressions should expire. Mailboxes that were full 6 months ago might be fine now. Permanent suppression for soft bounces loses you legitimate recipients over time.
When someone unsubscribes or complains, do not send them a confirmation or win-back email. They asked to stop receiving email. Send them more email and you risk another complaint, which compounds the reputation damage.
[email protected] goes to a shared inbox. Multiple people see your cold email. Any one of them can report it as spam. Role accounts have disproportionately high complaint rates for unsolicited mail.
data-ai
Choose and configure an email service provider. Use when setting up email for a new project, comparing providers, migrating between providers, or adding failover.
development
Set up SPF, DKIM, and DMARC email authentication. Use when configuring a new sending domain, debugging spam/rejection issues, adding email providers, or preparing for Google/Yahoo/Microsoft bulk sender requirements.
development
Design and send transactional emails. Use when building password resets, receipts, shipping notifications, account alerts, or separating transactional from marketing streams.
development
Build welcome and activation email sequences. Use when designing signup flows, driving users to key actions, converting trials to paid, or reducing early churn.