Suppressions
Manage email suppressions and unsubscribes
Suppressions prevent Postkit from sending to email addresses that have bounced, complained, or been manually blocked. Managing suppressions protects your sender reputation and ensures you only send to valid, willing recipients.
Prerequisites: An API key is required for all suppression management. See API Keys.
How suppressions work
When an email hard-bounces or a recipient marks your email as spam, Postkit automatically adds a suppression. Future sends to that address are blocked before they reach the SMTP engine, protecting your domain reputation.
There are three suppression reasons:
hard_bounce-- The recipient's mail server permanently rejected delivery. This typically means the address does not exist or the domain is unreachable.complaint-- The recipient marked your email as spam via a feedback loop (e.g., clicking "Report Spam" in their inbox).manual-- You manually suppressed the address via the API. Common use case: a user requests to stop receiving emails from your application.
When you attempt to send an email to a suppressed address, the API returns an error and the email is not queued for delivery.
List suppressions
Retrieve your suppression list with optional filtering by reason. The response uses cursor-based pagination.
# List all suppressions
curl https://api.postkit.eu/v1/suppressions \
-H "Authorization: Bearer pk_live_abc123..."
# Filter by reason
curl "https://api.postkit.eu/v1/suppressions?reason=hard_bounce" \
-H "Authorization: Bearer pk_live_abc123..."// List all suppressions
const response = await fetch('https://api.postkit.eu/v1/suppressions', {
headers: { 'Authorization': 'Bearer pk_live_abc123...' },
});
const { data, has_more } = await response.json();
// Filter by reason
const bounces = await fetch(
'https://api.postkit.eu/v1/suppressions?reason=hard_bounce',
{ headers: { 'Authorization': 'Bearer pk_live_abc123...' } }
).then(r => r.json());import requests
headers = {'Authorization': 'Bearer pk_live_abc123...'}
# List all suppressions
response = requests.get(
'https://api.postkit.eu/v1/suppressions',
headers=headers,
)
result = response.json()
# result['data'] is the array, result['has_more'] for pagination
# Filter by reason
bounces = requests.get(
'https://api.postkit.eu/v1/suppressions',
headers=headers,
params={'reason': 'hard_bounce'},
).json()The response includes a data array of suppression objects and a has_more boolean. Each suppression contains:
| Field | Type | Description |
|---|---|---|
id | string | Suppression ID (prefixed with sup_) |
email | string | The suppressed email address |
reason | string | One of hard_bounce, complaint, or manual |
detail | string or null | Bounce message or complaint feedback (if available) |
created_at | string | When the suppression was created (ISO 8601) |
Check if an address is suppressed
Query the suppression list for a specific email address to check whether it is currently suppressed:
curl "https://api.postkit.eu/v1/suppressions?email=user@example.com" \
-H "Authorization: Bearer pk_live_abc123..."const response = await fetch(
'https://api.postkit.eu/v1/suppressions?email=user@example.com',
{ headers: { 'Authorization': 'Bearer pk_live_abc123...' } }
);
const { data } = await response.json();
if (data.length > 0) {
console.log(`Suppressed: ${data[0].reason} (${data[0].created_at})`);
} else {
console.log('Not suppressed');
}response = requests.get(
'https://api.postkit.eu/v1/suppressions',
headers=headers,
params={'email': 'user@example.com'},
)
data = response.json()['data']
if data:
print(f"Suppressed: {data[0]['reason']} ({data[0]['created_at']})")
else:
print('Not suppressed')Add a manual suppression
Add an email address to the suppression list manually. This is useful when a user requests to stop receiving emails from your application.
curl -X POST https://api.postkit.eu/v1/suppressions \
-H "Authorization: Bearer pk_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"reason": "manual"
}'const response = await fetch('https://api.postkit.eu/v1/suppressions', {
method: 'POST',
headers: {
'Authorization': 'Bearer pk_live_abc123...',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'user@example.com',
reason: 'manual',
}),
});
const suppression = await response.json();
// suppression.id = "sup_abc123..."response = requests.post(
'https://api.postkit.eu/v1/suppressions',
headers={'Authorization': 'Bearer pk_live_abc123...'},
json={
'email': 'user@example.com',
'reason': 'manual',
},
)
suppression = response.json()
# suppression['id'] = "sup_abc123..."Only manual is accepted as the reason when creating suppressions via the API. The hard_bounce and complaint reasons are set automatically by Postkit when bounces or complaints are detected.
Remove a suppression
Delete a suppression to allow future sends to that address:
curl -X DELETE https://api.postkit.eu/v1/suppressions/sup_abc123... \
-H "Authorization: Bearer pk_live_abc123..."const response = await fetch(
'https://api.postkit.eu/v1/suppressions/sup_abc123...',
{
method: 'DELETE',
headers: { 'Authorization': 'Bearer pk_live_abc123...' },
}
);
const result = await response.json();
// result = { id: "sup_abc123...", deleted: true }response = requests.delete(
'https://api.postkit.eu/v1/suppressions/sup_abc123...',
headers={'Authorization': 'Bearer pk_live_abc123...'},
)
result = response.json()
# result = {'id': 'sup_abc123...', 'deleted': True}Removing a hard_bounce suppression and resending to an invalid address will result in another bounce, which harms your domain reputation. Only remove suppressions if you have confirmed the address is now valid (e.g., the recipient fixed their mailbox).
Automatic suppressions from webhooks
When Postkit detects a hard bounce or spam complaint, it automatically creates a suppression and sends a webhook event:
email.bouncedwithbounce_type: "hard"-- Postkit has created ahard_bouncesuppressionemail.complained-- Postkit has created acomplaintsuppression
Your application does not need to manually create these suppressions -- they are handled automatically. You can use these webhook events to update your own records (e.g., flag a user's email as invalid in your database).
See the Webhooks guide for setting up webhook endpoints and verifying signatures.
What's next?
- Webhooks -- receive bounce and complaint events in real time
- Error Handling -- understand API error responses