Check a message before it goes out, not after it bounces.
An email deliverability API takes a message you are about to send and returns what a receiving server is likely to hold against it: an unverified sending domain, marketing mail with no unsubscribe link, spam-filter symbols, suspicious links, an oversized body. It reports on the message and its domain, not on the recipient. Notix exposes its own check as POST /v1/deliverability/check, returning a verdict, a score from 0 to 100 and a list of findings, each with a fix.
Deliverability before a send, and after.
Deliverability is usually discussed after the fact: the bounce rate, the complaint rate, the share of mail that landed in spam. Those are measurements of what receiving servers decided, and by the time you have them the campaign has gone. The decision they made rests on three things. Reputation is the history of your sending domain and IPs, which a new sender has not earned yet and cannot inspect. Authentication is whether SPF, DKIM and DMARC say the mail is really yours. Content is the message itself: its links, images, wording and structure, which is what spam filters score.
Only the last two are visible before a send, and only content is fully within the message you are about to hand over. A pre-send check works on that layer: it renders the message the way a recipient would receive it, runs a spam filter over it, follows its links, and inspects the sending domain’s records. It turns the after-the-fact question “why did that land in spam?” into a before-the-fact one you can act on.
What a pre-send check can tell you, and what it cannot.
It can tell you that the domain in your from address is not verified for sending, which most receivers reject outright. It can tell you that a marketing message has no unsubscribe link, which providers and several jurisdictions require. It can tell you that a spam filter fires on your message and which rules fired, that a link points at a raw IP address or a URL shortener, that an image has no alt text, that the subject is shouting, that a template variable was left unrendered, that the HTML is over 100 KB, or that the domain has no DMARC record.
It cannot tell you what a particular mailbox provider will do. Gmail, Outlook and the rest weigh your reputation with them, the recipient’s past behaviour and signals they do not publish. A message can pass every visible check and still be filtered because the domain sent to a stale list last month. The honest framing is that a check removes the avoidable causes of rejection; it does not promise the inbox.
What the Notix check returns.
The request carries the from address and subject, and either the html body (with an optional text part) or a saved templateId with the variables to render it. A marketing flag says whether the unsubscribe rule applies. The response is one report:
- verdict:
PASS,WARNorBLOCK. It is BLOCK when any block finding is present, WARN when any warn finding is present, else PASS. - score: 0 to 100, higher is better. It starts at 100 and loses 5 points per spam-filter point, 15 per warning and 40 per block finding, floored at zero.
- findings: each with a stable
id, aseverityof block, warn or info, a title, the detail, and afixwritten to be acted on. Ordered block first, then warn, then info. - spam: whether the filter answered, its score (higher is worse) and the rules that fired with their descriptions.
- checkedAt and budgetExceeded: when the report was built, and the ids of any checks that did not finish inside the 15-second budget.
Four findings block. domain_unverified: the from domain is not one of your verified sending domains. unsubscribe_missing: marketing content with no unsubscribe link. link_ip_host: an anchor whose host is a raw IPv4 or IPv6 address. spam_high: the filter scored the message at 10 or more. The warnings cover a medium spam score (4 to 10, with the fired rules named), unreachable or plain-http links, link text that does not match its target, URL shorteners, images without alt text or with almost no visible text beside them, HTML over 102,400 bytes, subjects that are too long, mostly upper case or end in a run of punctuation, unrendered template variables, and a sending domain without a DMARC record. Two infos observe a missing preview text and a missing plain text part.
One request, one report.
Send exactly one of html or templateId. The endpoint answers 200 whenever the message could be rendered; the verdict inside tells you whether a send would be refused.
curl https://app.usenotix.dev/api/v1/deliverability/check \
-H "Authorization: Bearer $NOTIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "news@acme.com",
"subject": "Your September update",
"html": "<p>Read the update. <a href=\"https://acme.com/update\">Open it</a></p>",
"marketing": true
}'
import { Notix } from "notix-js";
const notix = new Notix(process.env.NOTIX_API_KEY);
const { data: report, error } = await notix.deliverability.check({
from: "news@acme.com",
subject: "Your September update",
html: "<p>Read the update. <a href=\"https://acme.com/update\">Open it</a></p>",
marketing: true,
});
if (report?.verdict === "BLOCK") {
for (const finding of report.findings) {
console.log(finding.severity, finding.title, "->", finding.fix);
}
}
import os
import requests
report = requests.post(
"https://app.usenotix.dev/api/v1/deliverability/check",
headers={"Authorization": f"Bearer {os.environ['NOTIX_API_KEY']}"},
json={
"from": "news@acme.com",
"subject": "Your September update",
"html": "<p>Read the update. <a href=\"https://acme.com/update\">Open it</a></p>",
"marketing": True,
},
).json()
if report["verdict"] == "BLOCK":
for finding in report["findings"]:
print(finding["severity"], finding["title"], "->", finding["fix"])
{
"verdict": "WARN",
"score": 85,
"findings": [
{
"id": "image_alt_missing",
"severity": "warn",
"title": "An image has no alt text",
"detail": "Filters and screen readers see an image with nothing to describe it.",
"fix": "Give every image a short alt attribute."
},
{
"id": "text_part_missing",
"severity": "info",
"title": "There is no plain text alternative",
"detail": "Some clients and filters prefer a text part beside the HTML.",
"fix": "Send a text version alongside the HTML."
}
],
"spam": {
"available": true,
"score": 2.4,
"symbols": [
{ "name": "HTML_SHORT_LINK_IMG_1", "score": 2, "description": "The email is mostly an image with a link" }
]
},
"checkedAt": "2026-09-07T12:00:00.000Z",
"budgetExceeded": []
}
Where to put it in your pipeline.
The check is an API request, not a send, so it costs none of your email allowance; it only counts against the team’s ordinary API rate limit. That shapes where it belongs. Run it when a template is saved, so a broken link or a missing alt is caught by the person who can fix it. Run it in CI against your rendered templates with representative variables, so an unrendered {{ name }} fails the build rather than the customer. Run it before every campaign, which Notix already does for you. Do not wire it in front of every individual transactional send: those messages come from templates you have already checked, and the extra round trip buys nothing.
Treat the three severities differently. A block is a bug: fail the pipeline. A warning is a review item: surface it to whoever owns the template and move on. An info is a suggestion you can batch up.
How Notix handles it.
The same report drives the product. When a team sends a campaign, Notix runs the check first and refuses on BLOCK with the findings shown in place of the confirmation; a WARN shows the warnings once with a “Send anyway”. Activating a journey checks every email step the same way. The template editor shows the panel too, so problems are visible while the message is being written. The spam scoring runs inside the Notix stack rather than through a third-party service, and if that filter is unreachable the report says so and nothing is blocked by the outage. For the transactional email API the check is advisory: you call it on your templates, and the email API sends what you ask it to. Every verified domain, the shared suppression list and the delivery webhooks sit around both paths.
Questions, answered.
What is an email deliverability API?
Does a pre-send check guarantee delivery to the inbox?
Does calling the check cost anything?
What happens when the spam filter is down?
Which findings actually stop a send?
Keep reading.
Email deliverability and sender reputation
What mailbox providers score, the complaint threshold that matters, warming a new domain, and the honest position on shared IPs.
ProductTransactional email API
OTPs, receipts and alerts with idempotency keys, a deliverability pre-check and a shared suppression list.
LearnEmail suppression lists
Why a suppression list exists, the three reasons an address lands on it, and why one list across transactional and marketing matters.
Use casesOTP email
Send one-time codes by email or SMS with two API calls, with expiry, length and risk scoring handled for you.
GuidesTransactional email in Node.js, production-ready
Idempotency keys, batch sends, a webhook handler, templates, the error envelope and retries on the typed SDK.
NotixDocs
The quickstart: verify a domain, copy an API key, send the first email.
Read the docs before you decide.
The endpoint, the request fields and every finding id are in the API reference.