Probeer het in de sandbox → Elk endpoint, met een knop die het uitvoert op de live service. Hiervoor is geen sleutel nodig, dus een verzoek dat je vanaf deze pagina verstuurt is echt: het reserveert een echt adres en telt mee.
De cyclus
Twee verzoeken en één e-mail. De derde aanroep is alleen nodig omdat de analyse enkele seconden duurt.
Reserveer een adres
Stuur een POST-verzoek naar het inbox-endpoint. Je krijgt een adres terug dat precies één bericht accepteert en na een uur verloopt, plus de slug waaraan al het andere is gekoppeld.
Stuur het echte bericht ernaartoe
Via SMTP, vanaf het platform dat de campagne zal verzenden. De helft van de controles leest headers die je verzendplatform toevoegt, dus een handmatig opgesteld bericht meet het verkeerde.
Poll de status en lees daarna het rapport
Het status-endpoint is enkele honderden bytes groot en vertelt je of het volledige rapport al kan worden opgehaald. Het rapport zelf beslaat enkele duizenden regels.
# 1. reserve a single-use address curl -sX POST 'https://email-spam-tester.com/api/v1/inbox?lang=en' { "address": "test-<slug>@t.email-spam-tester.com", "slug": "<slug>", "expires_at": "2026-01-01T12:00:00Z" }
# 2. send your message to that address, then poll curl -s 'https://email-spam-tester.com/api/v1/tests/<slug>/status' { "slug": "<slug>", "analysis_status": "checks_ready", "ai_status": "running", "checks_done": 39, "checks_total": 39 }
# 3. read the report once analysis_status is checks_ready curl -s 'https://email-spam-tester.com/api/v1/tests/<slug>' { "report_url": "https://email-spam-tester.com/t/<slug>", "score_ours": 86.4, "score_compat": 9.2, "subscores": {"auth": 100.0, "infra_spam": 78.1, "content": 92.0, "compliance": 75.0}, "complete": true, "checks": [ { "id": "auth.dmarc", "status": "warn", "title": "DMARC result", "summary": "DMARC passes, but the policy is p=none.", "weight_ours": -4.0, "evidence": {"policy": "none", "aligned": "dkim"}, "citations": {"standards": [{"title": "RFC 9989 §4.7", "quote": "..."}]} } ], "fixes": [ {"id": "dmarc-enforce", "gain_ours": 4.0, "gain_compat": 0.0, "fix": {"title": "Move DMARC to quarantine", "severity": "medium"}} ] }
Authenticatie
Die is er niet. Geen sleutel om aan te vragen, geen header om in te stellen, geen account om aan te maken. De slug die je terugkrijgt is de toegang: wie deze bezit, kan dat rapport lezen, en niemand anders kan deze raden.
Endpoints
Basisadres https://email-spam-tester.com. Alles retourneert JSON.
POST/api/v1/inbox
Reserveert een adres voor eenmalig gebruik. Beide parameters zijn optioneel.
| lang | Taal waarin het verbeterplan en de bevindingen per controle worden geschreven, als ISO-code. Wordt nu bepaald omdat het bericht minuten later via SMTP binnenkomt en geen aanwijzing bevat over wie erop wacht. Bij een onbekende code wordt teruggevallen op Engels. |
| utm_source, utm_medium, utm_campaign | Worden doorgegeven aan onze analytics. Nuttig als je je eigen integratie meet. |
GET/api/v1/tests/{slug}/status
Goedkoop om te pollen. Retourneert de twee statusvelden en hoe ver de controles zijn gevorderd, en verder niets.
GET/api/v1/tests/{slug}
Het volledige rapport. Retourneert 202 zolang het adres is gereserveerd en er nog niets is binnengekomen, en 200 zodra dat wel het geval is.
GET/api/v1/tests/{slug}/message
Het bericht precies zoals het is afgeleverd: elke header in transmissievolgorde, beide berichtteksten, de lijst met bijlagen en de onbewerkte bron. Wordt afzonderlijk opgehaald omdat het rapport wordt gepolld en dit tot een megabyte groot kan zijn.
PUT/api/v1/tests/{slug}/locale
Wijzigt de taal van een reservering die nog niet is gebruikt. Voor een agent die pas ontdekt welke taal zijn gebruiker leest nadat deze al om het adres heeft gevraagd. Wordt geweigerd zodra het bericht is aangekomen, omdat de analyse dan al wordt uitgevoerd.
GET/api/health
Liveness. Geen authenticatie, geen bijwerkingen.
Het rapport lezen
De velden die het antwoord bevatten, in de volgorde waarin u ze waarschijnlijk wilt lezen.
| score_ours | 0 tot 100. Ons model. Authenticatie en infrastructuur wegen het zwaarst, omdat zij de bezorging bepalen voordat een filter ook maar één woord van de tekst leest. |
| score_compat | 0 tot 10. Reproduceert het SpamAssassin-achtige getal dat mensen al gebruiken om te vergelijken, zodat het rapport vergelijkbaar is met wat iemand elders heeft gezien. |
| subscores | Dezelfde schaal van 0 tot 100 per sectie: auth, infra_spam, content, compliance. |
| checks[] | Alle 41, elk met een status, een bevinding van één regel, het bewijs waarop de beslissing is gebaseerd en hoeveel punten dit in beide scores kostte. |
| checks[].citations | Waar de bevinding vandaan komt: de sectie van de RFC, letterlijk geciteerd, en de pagina waarop Google zijn eigen vereiste vermeldt. Handmatig samengesteld in plaats van gegenereerd, zodat erop kan worden vertrouwd. |
| oplossingen[] | Wat moet worden gewijzigd, in de juiste volgorde, met het aantal punten dat elke wijziging waard is. De winst wordt berekend door het rapport opnieuw te scoren, niet geschat. |
| volledig | Onwaar wanneer een controle niet kon worden uitgevoerd. Een niet-gecontroleerd item geldt nooit als geslaagd, dus beschouw de score als optimistisch totdat dit waar is. |
| rapport_url | De voor mensen leesbare pagina. Geef die aan een persoon in plaats van een muur van JSON. |
Statussen
Een controle is een van vijf dingen, en het verschil tussen twee ervan is belangrijker dan het lijkt.
| geslaagd | De controle is uitgevoerd en heeft niets verkeerds gevonden. |
| waarschuwing | De moeite waard om op te lossen. Kost punten. |
| mislukt | Kost je bezorging. Kost meer punten. |
| overslaan | Niet van toepassing. Geen bijlagen om te scannen, geen HTML-gedeelte om te wegen. Niet geslaagd. |
| fout | We konden dit niet vaststellen. Uitgesloten van de score en gemarkeerd, in plaats van als geslaagd meegeteld. |
analysis_status doorloopt received, analyzing, checks_ready, failed. ai_status doorloopt pending, running, ready, fallback, error. Het deterministische rapport is definitief bij checks_ready; ai_status voegt alleen het plan toe.
Wat kan worden teruggegeven
| 202 | Het adres is gereserveerd en er is geen bericht aangekomen. De hoofdtekst bevat het adres, de vervaldatum en de taal, zodat een aanroeper die de reservering niet heeft aangemaakt deze toch kan weergeven. |
| 404 | Deze slug bestaat niet. Deze heeft nooit bestaan of de reservering is vergeten. |
| 410 | Het adres is verlopen voordat er een bericht aankwam. |
| 409 | U hebt geprobeerd de taal te wijzigen nadat het bericht al was aangekomen. |
| 429 | De limiet voor gratis tests voor uw adres. Er geldt momenteel geen limiet per persoon voor deze service; als die ooit wordt ingesteld, vermeldt de hoofdtekst wanneer deze opnieuw wordt ingesteld. |
Vier dingen om te weten
Eén bericht per adres
Het tweede wordt geweigerd. Je eerdere rapport blijft intact, wat precies de bedoeling is.
Een uur om het te gebruiken
Het adres verloopt; het rapport niet. Rapportlinks zijn permanent, dus een link die in een ticket is geplakt, blijft werken.
Verzenden vanaf het platform
Als je een campagne vanuit een persoonlijk account test, meet je dat account. Bijna alles in het gedeelte over authenticatie gaat over de verzendinfrastructuur, niet over de tekst.
Opnieuw testen na herstel
De verwachte verbeteringen worden per oplossing berekend en kunnen niet worden gecombineerd. Het tweede rapport geeft het eerlijke getal.
Voor machines
- /api/openapi.json De OpenAPI-beschrijving, gegenereerd op basis van dezelfde code die de API uitvoert.
- /llms.txt, /llms-full.txt Een korte kaart van deze site voor taalmodellen, volgens de llms.txt-conventie, en een langere versie met de volledige cyclus en de rapportvelden in één bestand.
- /mcp Een MCP-server met dezelfde functionaliteit en een blokkerende wachtfunctie, wat beter werkt dan pollen vanuit een model.
- For agents De agentpagina: wanneer je dit gebruikt, hoe je een overgeslagen controle ten opzichte van een geslaagde controle interpreteert, en welke bevindingen DNS-records zijn die een persoon moet wijzigen in plaats van tekst die een agent kan bewerken.
Probeer er eerst één handmatig
Het duurt ongeveer een minuut en laat je precies zien wat de JSON beschrijft.