The loop
Five steps, and the agent runs all of them without being walked through each one.
Get an address
One call reserves a single-use address and tells the agent which language to write the fix plan in. The address takes exactly one message and expires in an hour.
Send the real message to it
Not a summary, not a shortened version. Half the checks read headers the sending platform adds, and a pasted body carries none of them.
Wait
One blocking call. It returns when the analysis is finished, so the agent has nothing to poll and no sleep loop to get wrong.
Fix what it names
Each finding comes with the RFC section and the Google documentation page behind it, so the agent can check the claim instead of trusting it.
Send again
A new address, the corrected message, a second score to compare against the first. Expected gains are computed by re-scoring, but they do not compose, and the second report is the honest number.
Wire it up
The MCP server is one line for Claude Code:
claude mcp add --transport http email-spam-tester https://email-spam-tester.com/mcp
Or, for a client that takes JSON:
{
"mcpServers": {
"email-spam-tester": {
"type": "http",
"url": "https://email-spam-tester.com/mcp"
}
}
}
Four tools arrive with it: reserve an address, wait for the report, read an existing report by its slug, and fetch the message source exactly as it was delivered.
The skill file
MCP gives the agent the tools. This gives it the judgement: when to reach for them, how to read a status of skip against a status of pass, and which findings are DNS records the person has to change rather than text the agent can edit. Drop it in and the agent stops asking.
Save it as .claude/skills/mail-vet/SKILL.md, or paste it into whatever your client calls the same thing.
Without an agent
Two requests, no key. The first reserves the address, the second reads the report: 202 while nothing has arrived, 200 with everything once it has.
# reserve a single-use address curl -sX POST 'https://email-spam-tester.com/api/v1/inbox?lang=en&utm_source=agent' # {"address":"test-<slug>@email-spam-tester.com","slug":"<slug>",...} # send the message there, then read it back curl -s 'https://email-spam-tester.com/api/v1/tests/<slug>' # 202 while nothing has arrived, 200 with the report once it has
The response carries report_url, which is the page a person can read. Hand that over rather than a wall of JSON.
Reading the report
Two numbers, and they are not two opinions of the same thing.
Inbox score, 0 to 100
Our model. Authentication and infrastructure carry most of the weight, because they decide delivery before a filter reads a word of the copy.
Classic score, 0 to 10
Reproduces the SpamAssassin-style number people already compare against. It is here so the report is comparable to what somebody saw elsewhere, not because it measures better.
A check passes, warns, fails, is skipped, or errors. Skipped is not a pass: it means the check did not apply, with no attachments to scan or no HTML part to weigh. An error means we could not find out, which is worth saying out loud rather than scoring as though we had.
What the draft cannot fix
Some findings are DNS, not content, and the agent should say so plainly instead of editing the message until the score moves:
- SPF, DKIM and DMARC records, and whether they align with the From domain
- reverse DNS for the sending IP, and whether it forward-confirms
- MX records, TLS on the sending host, and blocklist entries
- MTA-STS, TLS reporting, DNSSEC and BIMI
Everything else is the draft: subject, preheader, HTML weight, the text part, image alt text, link shorteners, unsubscribe headers.
Four habits worth teaching it
Test what you are going to send
A rewritten sample measures the sample.
Send from the platform, not from your own client
Testing a Mailchimp campaign from a personal account measures that account.
Re-test after fixing
Fixes interact. The only number that accounts for that is the second report.
Do not test somebody else's mail without asking
The report shows the subject, the sender, the bounce address and the full source to anyone holding the link.
Test one by hand first
It takes about a minute and it shows you what the agent will be reading.