Suppressions

Block sends to addresses that bounced, complained, or were added manually. Suppressions are tenant-local to your Groundmail account.

Base URL: https://api.groundmail.dev


Authentication

Authorization: Bearer gm_…

Requires a full-scope API key (or dashboard session). Sending-scoped keys cannot manage suppressions.


Behavior

  • Emails are stored normalized lowercase.
  • Hard bounces, permanent SMTP delivery failures (e.g. invalid mailbox / 5xx), and complaint-like events auto-add suppressions (source: bounce / complaint).
  • Managed unsubscribe links add suppressions with source: unsubscribe.
  • POST /emails checks to / cc / bcc before sending. If any recipient is suppressed, the API returns 422 with code: validation_error, details.suppressed, and emits email.suppressed (a suppressed email record is created).

List

GET /suppressions

Query: limit, cursor, optional email.

{
  "data": [
    {
      "id": "…",
      "email": "bad@example.com",
      "reason": "550 user unknown",
      "source": "bounce",
      "created_at": "2026-07-26T12:00:00.000Z",
      "updated_at": "2026-07-26T12:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Add

POST /suppressions

{ "email": "user@example.com", "reason": "manual opt-out" }

source is set to api. Upserts on (account, email).


Remove

DELETE /suppressions/{id}

or

DELETE /suppressions?email=user@example.com

{ "ok": true }

SDK

import { Groundmail } from 'groundmail'

const client = new Groundmail(process.env.GROUNDMAIL_API_KEY!)

await client.suppressions.create({ email: 'user@example.com', reason: 'opt-out' })
const { data } = await client.suppressions.list()
await client.suppressions.remove('user@example.com')

CLI

groundmail suppressions list
groundmail suppressions add --email user@example.com --reason "opt-out"
groundmail suppressions remove --email user@example.com

OpenAPI

openapi/groundmail.yaml