MailLandDocs

Suppressions

Manage suppression lists to prevent sending to invalid, unsubscribed, or complained addresses

The suppression list prevents emails from being sent to addresses that have bounced, unsubscribed, or filed complaints. MailLand manages suppressions automatically from bounce and complaint events, and you can add or remove entries manually through the API.

Suppression Types

TypeValueDescriptionDefault Scope
HardBounce1Permanent delivery failureGlobal (always)
SoftBounce2Temporary failure (30-day Marketing suppression, escalates only after ≥3 eligible bounces across ≥7 days)Marketing (30-day expiry)
Complaint3Recipient marked email as spamGlobal (always)
Unsubscribe4Recipient opted outDepends on message type
Manual5Added manually via API or dashboardAny scope
Invalid6Invalid email formatGlobal (always)
SpamTrap7Known spam trap addressGlobal (always)
RoleAddress8Role-based email (info@, admin@, etc.)Global (always)

Suppression Scopes

Scopes control which types of emails are blocked:

ScopeValueBehavior
Global0Blocks all emails (transactional and marketing)
Marketing1Blocks marketing emails; transactional emails still delivered
Transactional2Blocks transactional emails only (rare)
List3Blocks emails for a specific mailing list only

Scope constraints:

  • HardBounce, Complaint, Invalid, SpamTrap, RoleAddress → Global scope only
  • SoftBounce → typically Marketing scope
  • Unsubscribe → Global, Marketing, or List (not Transactional)
  • Manual → any scope

List Suppressions

GET https://api.mail.land/v1/transactional/suppressions

Authenticate with Authorization: Bearer <token> or X-API-Key: <api key>.

List suppressions
curl https://api.mail.land/v1/transactional/suppressions \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

Query Parameters

ParameterTypeDefaultDescription
cursorstring-Opaque cursor from the previous page's nextCursor. Omit for the first page.
limitint50Items per page (max 100)
searchstring-Filter by email address
typeSuppressionType-Filter by type
scopeSuppressionScope-Filter by scope
mailingListIdstring-The mailing list's public id, resolved inside your tenant. An unknown, foreign or numeric id returns 404.
fromDatedatetime90 days agoStart date
toDatedatetimeNowEnd date
sortBystringCreatedAtSort field
sortDescendingbooltrueSort direction
Suppression list response
{
  "items": [
    {
      "id": "k3v9x2m8q1w7z4",
      "email": "[email protected]",
      "suppressionType": "hardBounce",
      "scope": "global",
      "mailingListId": null,
      "mailingListName": null,
      "expiresAt": null,
      "reason": "550 5.1.1 The email account does not exist",
      "bounceType": "Hard",
      "bounceCategory": "invalid_recipient",
      "bounceCount": 1,
      "lastBounceAt": "2026-02-17T12:00:00Z",
      "unsubscribeSource": null,
      "campaignId": null,
      "subscriberId": null,
      "source": "webhook",
      "notes": null,
      "createdAt": "2026-02-17T12:00:01Z",
      "isLocked": false,
      "lockedReason": null
    }
  ],
  "nextCursor": "eyJ2IjoxLCJzIjoiY3JlYXRlZGF0OmRlc2MiLCJrIjoi...",
  "hasMore": true
}

mailingListId, campaignId and subscriberId are the related resource's public id, resolved inside your tenant: never the internal numeric row id. Each is null when the entry has no such link, or when the linked resource has since been deleted.

Suppression Stats

Get a summary of your suppression list:

GET https://api.mail.land/v1/transactional/suppressions/stats
Get suppression stats
curl https://api.mail.land/v1/transactional/suppressions/stats \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
Stats response
{
  "totalCount": 5000,
  "globalCount": 3000,
  "marketingCount": 1500,
  "transactionalCount": 200,
  "listCount": 300,
  "hardBounceCount": 2000,
  "softBounceCount": 1500,
  "complaintCount": 500,
  "unsubscribeCount": 700,
  "manualCount": 200,
  "invalidCount": 50,
  "spamTrapCount": 30,
  "roleAddressCount": 20,
  "expiringCount": 85,
  "lastSuppression": "2026-02-17T12:00:01Z"
}

The expiringCount shows soft bounces that will expire within the next 7 days.

Check if an Email is Suppressed

Single check

GET https://api.mail.land/v1/transactional/suppressions/[email protected]&messageType=Marketing
Check suppression
curl "https://api.mail.land/v1/transactional/suppressions/[email protected]&messageType=Marketing" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
ParameterTypeDefaultDescription
emailstring-Email address (required)
messageTypestringMarketingMarketing or Transactional
mailingListIdstring-The mailing list's public id, resolved inside your tenant. An unknown, foreign or numeric id returns 404.
Check response
{
  "email": "[email protected]",
  "isSuppressed": true,
  "messageType": "Marketing"
}

Bulk check

Check up to 1,000 emails at once:

POST https://api.mail.land/v1/transactional/suppressions/check-bulk
Bulk check suppressions
curl -X POST https://api.mail.land/v1/transactional/suppressions/check-bulk \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{"emails":["[email protected]","[email protected]","[email protected]"],"messageType":"Marketing","mailingListId":null}'
Bulk check request
{
  "emails": ["[email protected]", "[email protected]", "[email protected]"],
  "messageType": "Marketing",
  "mailingListId": null
}
Bulk check response
{
  "suppressedEmails": ["[email protected]"]
}

Add a Suppression

POST https://api.mail.land/v1/transactional/suppressions
Add suppression
curl -X POST https://api.mail.land/v1/transactional/suppressions \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","suppressionType":"Manual","scope":"Global","reason":"Customer requested removal from all lists","notes":"Ticket #4521"}'
Add suppression request
{
  "email": "[email protected]",
  "suppressionType": "Manual",
  "scope": "Global",
  "reason": "Customer requested removal from all lists",
  "notes": "Ticket #4521"
}
FieldTypeRequiredDefaultDescription
emailstringYes-Email address (max 255 chars)
suppressionTypestringNoManualSuppression type
scopestringNoGlobalSuppression scope
mailingListIdstringNo-The mailing list's public id, resolved inside your tenant. Required if scope is List; an unknown, foreign or numeric id returns 404.
reasonstringNo-Reason (max 500 chars)
notesstringNo-Internal notes

Returns 201 Created with the full suppression object. The Location header is /v1/transactional/suppressions: the list route, since there is no get-by-id endpoint. Use the body's id field to identify the created suppression, and the List or Check endpoints to look it up.

Bulk Add

Add up to 1,000 suppressions at once:

POST https://api.mail.land/v1/transactional/suppressions/bulk
Bulk add suppressions
curl -X POST https://api.mail.land/v1/transactional/suppressions/bulk \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{"emails":[{"email":"[email protected]","suppressionType":"Manual","scope":"Global","reason":"Cleanup"},{"email":"[email protected]","suppressionType":"Manual","scope":"Marketing"}]}'
Bulk add request
{
  "emails": [
    { "email": "[email protected]", "suppressionType": "Manual", "scope": "Global", "reason": "Cleanup" },
    { "email": "[email protected]", "suppressionType": "Manual", "scope": "Marketing" }
  ]
}
Bulk add response
{
  "totalCount": 2,
  "addedCount": 2,
  "skippedCount": 0,
  "skippedEmails": [],
  "message": "Added 2 suppressions"
}

Emails that already exist in the suppression list are skipped (not duplicated).

Import from CSV

From text content

POST https://api.mail.land/v1/transactional/suppressions/import
Import suppressions from CSV text
curl -X POST https://api.mail.land/v1/transactional/suppressions/import \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{"csvContent":"[email protected]\[email protected]\[email protected]","defaultReason":"Imported from legacy system","suppressionType":"Manual","scope":"Global"}'
CSV import request
{
  "csvContent": "[email protected]\n[email protected]\n[email protected]",
  "defaultReason": "Imported from legacy system",
  "suppressionType": "Manual",
  "scope": "Global"
}

From file upload

POST https://api.mail.land/v1/transactional/suppressions/import-file
Import suppressions from file
curl -X POST "https://api.mail.land/v1/transactional/suppressions/import-file?scope=List&mailingListId=123" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  -F "[email protected]"

scope and mailingListId are query parameters, not form fields: a form field with either name is silently ignored, so a List-scope import sent as a form field fails with 400. mailingListId is the list's public id, resolved inside your tenant; an unknown, foreign or numeric id returns 404.

Upload a .csv file (max 5 MB) with email addresses separated by commas or newlines. A header row containing "email" is automatically skipped.

Query parameters:

ParameterTypeDescription
filefile (multipart form field)CSV file (max 5 MB, .csv extension required)
scopestring (query)Suppression scope (default: Global)
mailingListIdstring (query)The mailing list's public id, resolved inside your tenant. Required if scope is List; an unknown, foreign or numeric id returns 404.
Import result
{
  "totalRows": 1000,
  "importedCount": 950,
  "skippedCount": 40,
  "invalidCount": 10,
  "invalidEmails": ["not-an-email", "missing-domain@", "..."],
  "errors": [],
  "message": "Imported 950 emails. 40 already existed. 10 invalid."
}

The invalidEmails list shows up to 10 invalid entries. Already-existing emails are counted as skippedCount, not errors.

Export Suppressions

Download your suppression list as CSV:

GET https://api.mail.land/v1/transactional/suppressions/export
Export suppressions
curl https://api.mail.land/v1/transactional/suppressions/export \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  -o suppressions.csv
ParameterTypeDescription
typeSuppressionTypeFilter by type
scopeSuppressionScopeFilter by scope
mailingListIdstringThe mailing list's public id, resolved inside your tenant. An unknown, foreign or numeric id returns 404.

Returns a CSV file with columns: email, type, scope, mailing_list, reason, bounce_count, source, created_at, expires_at. Limited to 100,000 rows.

Remove a Suppression

By ID

DELETE https://api.mail.land/v1/transactional/suppressions/{id}
Delete suppression by ID
curl -X DELETE https://api.mail.land/v1/transactional/suppressions/k3v9x2m8q1w7z4 \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

By email

DELETE https://api.mail.land/v1/transactional/suppressions/[email protected]
Delete suppression by email
curl -X DELETE "https://api.mail.land/v1/transactional/suppressions/[email protected]" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
ParameterTypeDescription
emailstringEmail to unsuppress (required)
scopeSuppressionScopeRemove only for this scope
mailingListIdstringRemove only for this mailing list: its public id, resolved inside your tenant. An unknown, foreign or numeric id returns 404.

Returns 204 No Content on success, 404 if not found.

Locked Suppressions

Certain suppressions cannot be deleted to protect your sender reputation and comply with anti-spam regulations:

Locked TypeReason
ComplaintSpam complaint: compliance requirement
SpamTrapKnown spam trap: deliverability protection
Unsubscribe via FeedbackLoopISP feedback loop
Unsubscribe via OneClickRFC 8058 one-click unsubscribe
Unsubscribe via ManualLinkUser confirmed unsubscribe
Unsubscribe via PreferenceUser preference center choice

Attempting to delete a locked suppression returns:

403 Forbidden
{
  "code": "SUPPRESSION_LOCKED",
  "message": "Cannot delete: Spam complaint - compliance requirement",
  "details": {
    "lockedReason": "Spam complaint - compliance requirement"
  }
}

Deleting complaint-based suppressions and resending to those addresses will damage your sender reputation and may violate anti-spam laws. These suppressions are locked for your protection.

Unsubscribe Sources

When a recipient unsubscribes, the source is recorded:

SourceValueDescriptionLocked
ListUnsubscribeHeader0RFC 8058 List-Unsubscribe headerNo
ListUnsubscribeMail1mailto: unsubscribeNo
WebForm2Web unsubscribe pageNo
Api3API callNo
Admin4Admin panelNo
FeedbackLoop5ISP feedback loopYes
OneClick6RFC 8058 POST one-clickYes
ManualLink7User confirmed via linkYes
Preference8Preference center choiceYes

Error Responses

StatusCodeDescription
400INVALID_REQUESTValidation failure (invalid email, scope, or type)
400INVALID_EMAIL_FORMATEmail address format is invalid
400CONTENT_TOO_LARGECSV file exceeds 5 MB
403SUPPRESSION_LOCKEDCannot delete a locked suppression
404RESOURCE_NOT_FOUNDSuppression not found, or a supplied mailingListId names no mailing list in your tenant

Next Steps

  • Bounces: understand bounce types and auto-suppression
  • Deliverability Overview: monitor sender reputation
  • Webhooks Events: receive message.bounced events (suppression.added/suppression.removed are defined in the catalog but never emitted today)

On this page