API reference
Suppressions
The suppression list is the set of addresses we refuse to mail. Sending to a suppressed address returns 422 instead of delivering.
Why use this
For example
A customer mistypes their address at signup, it hard-bounces, and they get suppressed. They fix the typo and write in asking why they get nothing — you remove the old address and they're unblocked.
Example
import { YourMail } from "yourmail";
const yourmail = new YourMail(process.env.YOURMAIL_API_KEY!, {
baseUrl: process.env.YOURMAIL_BASE_URL!,
});
// List
const page = await yourmail.listSuppressions({ limit: 50 });
// Add — the response reports "manual"; an existing stronger reason is kept
await yourmail.createSuppression("alice@example.com");
// Remove — idempotent, `removed` is false if it wasn't on the list
const { removed } = await yourmail.deleteSuppression("alice@example.com");// List
const res = await fetch("https://api.yourmail.dev/v1/suppressions?limit=50", {
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
// Add
await fetch("https://api.yourmail.dev/v1/suppressions", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({ email: "alice@example.com" }),
});
// Remove
await fetch(
"https://api.yourmail.dev/v1/suppressions/alice%40example.com",
{ method: "DELETE", headers: { Authorization: "Bearer YOUR_API_KEY" } }
);# List
curl "https://api.yourmail.dev/v1/suppressions?limit=50" \
-H "Authorization: Bearer YOUR_API_KEY"
# Add
curl -X POST https://api.yourmail.dev/v1/suppressions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"alice@example.com"}'
# Remove (URL-encode the address)
curl -X DELETE \
https://api.yourmail.dev/v1/suppressions/alice%40example.com \
-H "Authorization: Bearer YOUR_API_KEY"List suppressions
Cursor-paginated: read nextCursor from a response and pass it back as cursor until it comes back null. Both parameters are optional. Unlike the emails list, which is newest-first, suppressions come back ordered by address.
limitnumber- Page size, 1–100. Defaults to 50. Values outside the range are clamped.
cursorstring- Opaque cursor from a previous response's nextCursor. Omit to start at the beginning.
// 200 OK — GET /v1/suppressions
{
"data": [
{
"address": "alice@example.com",
"reason": "hard_bounce",
"createdAt": 1750000000000
}
],
"hasMore": false,
"nextCursor": null
}addressstring- The suppressed address, normalised to lower case.
reasonstring- Why it was suppressed. See the reasons below.
createdAtnumber- Unix millisecond timestamp when the address was suppressed.
Add a suppression
POST a JSON body of { "email": "..." }. The address is normalised to lower case. Adding an address that's already suppressed is safe.
The response always reports manual, but an address that was already suppressed keeps whichever reason blocks more mail: an existing hard_bounce or complaint is left as it is, while an unsubscribe is upgraded to manual so it blocks transactional mail too.
// 201 Created — POST /v1/suppressions
{
"address": "alice@example.com",
"reason": "manual"
}Remove a suppression
Put the address in the path, URL-encoded (@ becomes %40). The call is idempotent — removing an address that isn't suppressed returns 200 with removed: false rather than a 404. Once removed, the address can receive mail again immediately.
// 200 OK — DELETE /v1/suppressions/:address
{
"address": "alice@example.com",
"removed": true
}Suppression reasons
Not every suppression blocks everything. An unsubscribe is scoped to bulk mail, so a recipient who opts out of your newsletter still receives their password resets and receipts.
hard_bounceAll mailcomplaintAll mailmanualAll mailunsubscribeBulk onlyErrors
validation_errorBody isn't valid JSON, or the email field is missing or not a valid address
authentication_errorAPI key missing, malformed, or not recognised
authentication_errorThe key is send-only; suppressions require a full-access key