Loading tutorials…
Loading tutorials…
Suppressions are the dull, unglamorous part of email that decides whether your account survives the year. Gmail and Yahoo's 2024 bulk sender rules made one-click unsubscribe mandatory at scale, and SendGrid's suppression groups are how you respect that without losing transactional sends. Here's the full setup.
Who this is forSendGrid accounts sending both marketing AND transactional from the same domain — you need to give recipients a way to opt out of marketing without losing receipts. Or accounts that have been flagged for high complaint rate and need to tighten suppression hygiene.
What you'll need
Step 1
SendGrid has Global Unsubscribes, Group Unsubscribes (ASM), Bounces, Spam Reports, Invalid Emails, and Blocks. Each behaves differently.
Global Unsubscribes: blocks ALL future sends (marketing + transactional). Use rarely — usually for legal-removal requests.
Group Unsubscribes (ASM — Advanced Suppression Manager): blocks sends from a SPECIFIC group (e.g., "Marketing newsletter") while allowing other groups. THIS is what you want for marketing vs transactional separation.
Bounces: SendGrid auto-suppresses on hard bounces. Soft bounces auto-upgrade to hard after 5 in 30 days.
Spam Reports: SendGrid auto-suppresses when recipients hit the "Mark as spam" button. Critical signal — DO NOT remove these manually.
Invalid Emails: addresses that hard-bounced as malformed. Auto-suppressed.
Blocks: temporary suppression due to ISP rejection (e.g., "550 mailbox full"). Auto-clears after a few days.
Settings → Suppressions: see all 6 lists. Most accounts only need to actively manage Groups (ASM).
Step 2
SendGrid → Marketing → Unsubscribe Groups → Create New Group. Create groups for Marketing, Newsletter, Promotional, etc.
SendGrid → Marketing → Unsubscribe Groups → Create New Group.
Group 1: "Marketing Newsletter" — Description: "Weekly newsletter + product updates. Unsubscribe to stop receiving these emails."
Group 2: "Promotional Offers" — Description: "Sale announcements, discount codes, limited-time offers."
Group 3: "Product Updates" — Description: "Feature launches, changelogs, important account information."
Critical: do NOT create a group for transactional emails (receipts, password resets, order confirmations). Transactional should NEVER be suppressible — they're legally required for the customer's purchase + account access.
Note the Group ID for each (integer, shown in URL). Your code will pass this when sending — see Step 4.
Recommended: keep total groups to 3-5. More than 8 and recipients get confused on the unsubscribe page (showing 8+ checkboxes).
Step 3
When sending marketing emails via API or Marketing Campaigns, include `asm.group_id` to associate the send with a suppression group.
API send (Node): `await sgMail.send({ to, from, templateId, asm: { groupId: 12345, groupsToDisplay: [12345, 67890] } });`
`asm.group_id` = the group this send belongs to. If recipient unsubscribes from this email, they're added to this group's suppression.
`asm.groups_to_display` = which OTHER groups appear on the unsubscribe page. Lets recipients adjust preferences across multiple groups in one click.
Marketing Campaigns Single Sends: Settings tab → Unsubscribe Group → select the group. Same effect.
Transactional sends: omit the `asm` parameter entirely. They're not associated with any group and only Global Unsubscribes block them.
Test: send a marketing email tagged to a test address. Click the unsubscribe link. Should see ONLY the marketing group(s), not transactional types.
Step 4
Add List-Unsubscribe + List-Unsubscribe-Post headers. SendGrid does this automatically when ASM groups are configured — but verify it's in real headers.
Gmail and Yahoo's 2024 bulk sender rules (5K+ sends/day) require one-click unsubscribe — a header-level mechanism, not just a footer link.
SendGrid auto-adds List-Unsubscribe headers when ASM is configured. Verify by sending a marketing email to a Gmail address you control → Show original → check headers.
Expected headers: `List-Unsubscribe: <mailto:unsubscribe@sendgrid.net?subject=unsubscribe>, <https://u#######.ct.sendgrid.net/wf/unsubscribe?upn=...>` and `List-Unsubscribe-Post: List-Unsubscribe=One-Click`.
If these headers are MISSING: your send is not associated with an ASM group OR the template overrides headers. Fix by ensuring every marketing send uses `asm.group_id`.
Test in Gmail: open the email → click the "Unsubscribe" link Gmail offers in the header bar (next to From). Should unsubscribe in one click without leaving the inbox.
Verify suppression: SendGrid → Suppressions → Group Unsubscribes → test address should appear.
Step 5
Settings → Mail Settings → Bounce Purge → ON, 60 days. Lets recovered addresses retry after a reasonable window.
SendGrid → Settings → Mail Settings → Bounce Purge: ON, set duration 60 days.
What this does: bounced addresses stay suppressed for 60 days, then are removed from suppression. If the address recovers (mailbox unfrozen, domain rebought), future sends try again.
Without bounce purge: suppressions accumulate forever. Genuine recoveries are blocked. Reputation slowly degrades from sending to a stale suppression-skipped list.
Hard bounces (invalid email): purge after 60 days is fine — most have permanently moved on.
Spam Reports: NEVER purge. SendGrid keeps these forever by default. Re-sending to someone who marked you as spam is the fastest way to permanent reputation damage.
Manual cleanup: 1x/quarter, review Suppressions → Bounces for addresses you know have changed (e.g., employees who left). Remove from suppression only after confirming the address is now valid.
Step 6
Subscribe to bounce + complaint + unsubscribe events via Event Webhook (Tutorial 7). Update user records in your app.
Tutorial 7 covers webhook setup. The suppression-relevant events:
`bounce` (event=bounce): user has a bad address. Block future sends in YOUR app too.
`spamreport` (event=spamreport): user marked you as spam. Block ALL future sends. Update marketing_consent = false in your DB.
`unsubscribe` (event=unsubscribe): user unsubscribed from a specific group. Block marketing sends from that group.
Critical: maintain YOUR OWN suppression in your DB too. SendGrid maintains its list, your app maintains its list. Both block the same addresses. Belt + suspenders.
Why both: if you migrate off SendGrid later, your suppression history goes with you. SendGrid suppressions don't export to Mailchimp/Klaviyo automatically.
Step 7
Settings → Suppressions → review each list monthly. Remove only when you know the address is valid AND recipient explicitly opted back in.
Monthly: SendGrid → Suppressions → Bounces. Look for patterns: same domain bouncing (your contact at @company.com left), recent hard bounces (recent list imports may have stale addresses).
Monthly: Suppressions → Group Unsubscribes. Check counts — sudden spike means a campaign drove unsubscribes; investigate which.
Monthly: Suppressions → Spam Reports. Even one new report should be investigated — what campaign? what segment? Was it a content + audience mismatch?
Removing from suppression: only when you have explicit re-opt-in. Customer emails support saying "please re-add me" → manually remove from Group Unsubscribe list → also unsuppress in YOUR DB.
NEVER bulk-clear suppressions to "give people another chance." Recipients who unsubscribed will mark you as spam, escalating the damage.
Common mistakes
No ASM groups — using one global Unsubscribe for everything
What goes wrong: Recipient unsubscribes from a marketing promo → they're globally unsubscribed → they stop receiving order confirmations + password resets. Customer support tickets pile up. In regulated industries (finance, healthcare) this can trigger compliance issues.
How to avoid: Create ASM groups for marketing categories. Tag marketing sends with `asm.group_id`. Leave transactional sends untagged so they bypass group suppression entirely.
Tagging transactional sends with an ASM group
What goes wrong: Recipient unsubscribes (maybe accidentally clicking the wrong link) → stops receiving receipts + password resets → can't access their account. Major customer experience failure that's hard to recover from.
How to avoid: Send transactional WITHOUT the asm parameter. Marketing Campaigns Single Sends: leave Unsubscribe Group unset for transactional templates. Only marketing/promotional sends get an ASM group.
No List-Unsubscribe header (failing Gmail/Yahoo 2024 rules)
What goes wrong: At 5K+/day, Gmail and Yahoo BLOCK senders without one-click unsubscribe headers. Your marketing volume hits the wall. Recovery requires both fixing headers AND ~30-60 days of degraded reputation.
How to avoid: Ensure every marketing send includes an ASM group_id (which adds the headers automatically). Verify in real Gmail headers. Don't override headers in custom templates.
Bulk-clearing suppressions to "give them another chance"
What goes wrong: Removing 500 unsubscribers from suppression sends them another email. They marked unsubscribe for a reason. Many will hit 'Mark as spam' on the next email. Complaint rate spikes. Account compliance review.
How to avoid: Never bulk-clear. Only remove individuals after explicit re-opt-in (they emailed support, signed up again, etc.). Treat suppressions as permanent unless the user actively reverses.
Not syncing suppressions to your application DB
What goes wrong: SendGrid blocks the send but your app keeps trying to send. Your DB shows 'sent' but SendGrid logs 'dropped' (suppression). You think emails are working; customers report not receiving them. Debugging is painful.
How to avoid: Listen to bounce + unsubscribe + spamreport events via Event Webhook (Tutorial 7). Update user records: `email_status = bounced|unsubscribed|complained`. Block sends in YOUR app before they reach SendGrid.
Manual suppression list maintenance via CSV imports
What goes wrong: Some teams export suppressions, edit in Excel, re-import. Multi-step, error-prone, no audit trail. Easy to accidentally remove all bounces or import bad addresses.
How to avoid: Manage suppressions via the API or UI directly. For programmatic add/remove, use SendGrid's Suppression API endpoints. Never bulk CSV unless you know exactly what you're doing.
Recap
Done — what's next
How to set up SendGrid Event Webhooks with signature verification and idempotency
Read the next tutorial
Hand it off
Suppression management is one of those tasks that's easy to set up wrong and easy to overlook for months. A specialist will configure ASM groups, one-click unsubscribe, bounce purge, and webhook-driven sync in 4-6 hours — and audit your existing suppressions for unrecoverable damage. Typical engagement is $300-600 at $14-16/hr.
See specialist rates
Global Unsubscribe blocks ALL future sends (marketing + transactional). Use rarely, for legal removal requests. Group Unsubscribe (ASM) blocks sends from specific groups — so a user can unsubscribe from marketing while still receiving receipts. ASM is what 99% of accounts should use.
Not strictly required by Gmail/Yahoo's 2024 rules (which kick in at 5K/day), but it's good practice — Gmail downranks senders without one-click headers even at lower volume. Cost of adding: zero (SendGrid does it automatically with ASM). Always enable it.
Yes — SendGrid checks suppression lists before sending. Suppressed addresses get a `dropped` event (visible in Event Webhook) and the send doesn't go out. Doesn't count against your sending quota. Your app should also check suppression before queueing the send to save the API call.
Yes — SendGrid → Suppressions → click the suppression type → each address shows the reason (e.g., bounce reason text from the ISP). Useful for debugging patterns. Note: bounces are often opaque ('550 mailbox not found') — focus on whether bounce rate is normal, not on individual reasons.
Build a preference page in your app. When user clicks unsubscribe in an email, link to your preference page (override SendGrid's default unsubscribe landing page) where they can opt out of specific groups. Use SendGrid's Suppression API to update group memberships on save.
Storage-wise: none, SendGrid keeps suppressions indefinitely. Reputation-wise: suppression count alone isn't bad — high churn (lots of new unsubscribes per campaign) IS bad. Track unsubscribe rate per campaign (<0.5% is healthy); a growing suppression list with stable churn rate is just a maturing account.
SendGrid
Event Webhooks are how your app actually learns what happened to a send — delivered, opened, clicked, bounced, complained. The setup is 5 minutes; the production-grade version (signature verification, idempotency, retry handling) is 2 hours. Most teams skip the second part and find out at month 6 when payloads start no-op'ing.
SendGrid
SendGrid Marketing Campaigns is structurally different from Mailchimp or Klaviyo — it's a marketing layer bolted onto a developer-first sending platform. The UI feels like 'they tried.' For dev teams already on SendGrid for transactional, it's the path of least resistance. For marketing-first teams, Klaviyo or Brevo usually wins. Here's how to make it work.
SendGrid
Dynamic Templates are SendGrid's best-kept feature: template lives in SendGrid, your app sends a small JSON payload, marketing edits the design without touching code. But the Handlebars syntax, versioning, and dynamic_template_data shape have sharp edges that cost an afternoon to learn the hard way.
SendGrid
Open rate dropped from 28% to 14%. Bounces jumped. Customer support is forwarding 'we never got the email' tickets. The instinct is 'subject lines' or 'content' — usually it's deliverability infrastructure. Here's how specialists diagnose SendGrid deliverability without guessing.
SendGrid
DIY SendGrid is the right call until it isn't. The signal isn't 'sending more emails' — it's that the cost-of-mistakes finally outweighs the cost-of-hiring. Here's the honest framework for when that line is crossed.