Email Spam Tester

API di controllo spam: email,
posta in arrivo e dominio

Inviaci un messaggio reale oppure forniscici solo un dominio. Tutto viene restituito in JSON.

Nessuna chiave, nessun account.

Richiesta

# reserve a single-use address

$ curl -sX POST '.../api/v1/inbox?lang=en'

# send your message to that address, then

$ curl -s '.../api/v1/tests/k7m2x9qplw4tz8vn3b6c/status'

# read the report

$ curl -s '.../api/v1/tests/k7m2x9qplw4tz8vn3b6c'

Risposta

200 OK

{
  "address": "test-k7m2x9qplw4tz8vn3b6c@t.email-spam-tester.com",
  "slug": "k7m2x9qplw4tz8vn3b6c",
  "expires_at": "2026-10-31T13:00:00Z"
}

200 OK

{
  "analysis_status": "checks_ready",
  "ai_status": "running",
  "checks_done": 42,
  "checks_total": 42
}

200 OK

{
  "score_ours": 86.4,
  "score_compat": 9.2,
  "subscores": {"auth": 100.0, "infra_spam": 78.1, "content": 92.0},
  "complete": true,
  "checks": [{"id": "auth.dmarc", "status": "warn"}],
  "fixes": [{"id": "dmarc-enforce", "gain_ours": 4.0}]
}

Richiesta

# create a test

$ curl -sX POST '.../api/v1/placement' \ -d '{"public_results_accepted":true}'

# put the marker in the subject, send once to all, then

$ curl -s '.../api/v1/placement/wR3kP9xLq2vT8mZc'

Risposta

201 Created

{
  "marker": "est-3f9a1c7e2b4d6a80c5e1f2d3",
  "status": "waiting",
  "results": [{"provider": "gmail", "placement": "pending"}],
  "fleet": {"status": "observing", "results": [
    {"provider": "yahoo", "placement": "pending"},
    {"provider": "outlook", "placement": "pending"}
  ]}
}

200 OK

{
  "status": "complete",
  "results": [{"provider": "gmail", "placement": "primary"}],
  "fleet": {"status": "finished", "results": [
    {"provider": "yahoo", "placement": "inbox"},
    {"provider": "outlook", "placement": "spam"}
  ]}
}

Richiesta

# no email needed, one GET

$ curl -s '.../api/v1/infra/check?domain=example.com'

# compare with your last run

$ curl -s '.../api/v1/infra/check?domain=example.com&diff=true' \ | jq '.diff'

Risposta

200 OK

{
  "domain": "example.com",
  "ok": false,
  "status": "fail",
  "score": 78,
  "coverage": {"answered": 7, "total": 8},
  "sections": {"ptr": {"status": "fail", "core": true}}
}

200 OK

{
  "changed": true,
  "worsened": true,
  "status_from": "pass",
  "score_from": 100,
  "changes": [{"path": "dkim.key.mail.sha256", "kind": "removed",
               "severity": "critical", "effect": "worsened"}]
}
In questa pagina

Test email

Leggiamo un messaggio reale dall'inizio alla fine: contenuto, firma, intestazioni e il server che lo ha inviato. Ottieni un punteggio, un elenco di correzioni e tutti i controlli su cui si basano.

Avvio rapido

Tre chiamate. Nessuna chiave, nessun account, nessuna registrazione. Due richieste e un'email. La terza chiamata serve solo perché l'analisi richiede alcuni secondi.

  1. Riserva un indirizzo

    Invia una richiesta POST all'endpoint della casella di posta. Ricevi un indirizzo che accetta esattamente un messaggio e scade dopo un'ora, insieme allo slug su cui si basa tutto il resto.

    Richiesta

    # 1. reserve a single-use address
    curl -sX POST 'https://email-spam-tester.com/api/v1/inbox?lang=en'

    Risposta

    {
      "address": "test-<slug>@t.email-spam-tester.com",
      "slug": "<slug>",
      "expires_at": "2026-01-01T12:00:00Z"
    }
  2. Inviagli il messaggio reale

    Tramite SMTP, dalla piattaforma che invierà la campagna. Metà dei controlli legge le intestazioni aggiunte dalla piattaforma di invio, quindi un messaggio composto a mano misura la cosa sbagliata.

    Richiesta

    # 2. send your message to that address, from your own platform
    To: test-<slug>@t.email-spam-tester.com
  3. Interroga lo stato, quindi leggi il report

    L'endpoint di stato occupa poche centinaia di byte e indica se vale già la pena recuperare il report completo. Il report stesso si estende per diverse migliaia di righe.

    Richiesta

    # 3. poll
    curl -s 'https://email-spam-tester.com/api/v1/tests/<slug>/status'

    Risposta

    {
      "slug": "<slug>",
      "analysis_status": "checks_ready",
      "ai_status": "running",
      "checks_done": 42,
      "checks_total": 42
    }

    Richiesta

    # 4. read the report once analysis_status is checks_ready
    curl -s 'https://email-spam-tester.com/api/v1/tests/<slug>'

    Risposta

    {
      "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"}}
      ]
    }

Riserva un indirizzo, invia il messaggio che stavi per inviare alla tua lista, leggi il report. Tutto ciò che mostra la pagina è nel JSON, incluso il punteggio, tutti i 42 controlli con le relative evidenze e la sezione dello standard su cui si basa ciascun risultato.

I primi 100.000 report sono gratuiti, senza chiave e senza account. Se stai configurando un agente anziché uno script, il server MCP è più adatto del polling.

Endpoint

Indirizzo base https://email-spam-tester.com. Tutto risponde in JSON.

POST/api/v1/inbox

Riserva un indirizzo monouso. Entrambi i parametri sono facoltativi.

langLingua in cui verranno scritti il piano di correzione e i risultati di ogni controllo, come codice ISO. Viene decisa ora perché il messaggio arriva tramite SMTP alcuni minuti dopo e non contiene alcuna indicazione su chi lo sta aspettando. Un codice sconosciuto usa l'inglese come fallback.
utm_source, utm_medium, utm_campaignInoltrati alle nostre analisi. Utile se stai misurando la tua integrazione.

GET/api/v1/tests/{slug}/status

Economico da interrogare periodicamente. Restituisce i due campi di stato e l'avanzamento dei controlli, e nient'altro.

Interroga periodicamente questo anziché il report. analysis_status raggiunge prima checks_ready e il piano AI viene inserito in ai_status circa un minuto dopo, così un client che vuole solo i controlli deterministici non deve attendere il piano.

GET/api/v1/tests/{slug}

Il report completo. Risponde con 202 mentre l'indirizzo è riservato e non è ancora arrivato nulla, con 200 una volta ricevuto il messaggio.

GET/api/v1/tests/{slug}/message

Il messaggio esattamente come è stato recapitato: ogni intestazione nell'ordine di trasmissione, entrambi i corpi, l'elenco degli allegati e il sorgente grezzo. Viene recuperato separatamente perché il report viene interrogato periodicamente e questo può raggiungere un megabyte.

Il messaggio non elaborato viene eliminato secondo la propria scadenza, prima del report. Dopo quel momento questo endpoint risponde con il motivo anziché con il sorgente.

PUT/api/v1/tests/{slug}/locale

Cambia la lingua di una prenotazione che non è stata ancora utilizzata. Per un agente che apprende quale lingua legge il proprio utente dopo averne già richiesto l'indirizzo. La richiesta viene rifiutata una volta arrivato il messaggio, perché a quel punto l'analisi è in corso.

Posizionamento nella posta in arrivoBeta

Invia un messaggio a un elenco di caselle di posta di test e verifica dove è arrivato su Gmail, Outlook, Yahoo e altri provider: Posta in arrivo, Promozioni o Spam.

Avvio rapido

  1. Crea un test

    Esegui una richiesta POST all'endpoint di posizionamento. Riceverai un marcatore e le caselle di posta di test.

    Richiesta

    # 1. create a test
    curl -sX POST 'https://email-spam-tester.com/api/v1/placement' \
      -H 'Content-Type: application/json' \
      -d '{"public_results_accepted":true}'

    Risposta

    {
      "slug": "<slug>",
      "marker": "est-3f9a1c7e2b4d6a80c5e1f2d3",
      "status": "waiting",
      "deadline": "2026-10-31T12:30:00Z",
      "poll_after_seconds": 60,
      "results": [
        {"address": "<seed>", "provider": "gmail", "kind": "Gmail",
         "placement": "pending", "observed_at": null}
      ],
      "fleet": {
        "status": "observing",
        "results": [
          {"address": "<mailbox>", "provider": "yahoo", "available": true,
           "placement": "pending", "coverage": "pending"}
        ]
      }
    }
  2. Invia un messaggio a ogni casella

    Inserisci il marcatore nell'oggetto e invia il messaggio dalla tua piattaforma abituale a tutti gli indirizzi in un'unica operazione.

    Richiesta

    # 2. one message to every address, with the marker in the subject
    Subject: October invoice est-3f9a1c7e2b4d6a80c5e1f2d3
    To: <seed>, <mailbox>, ...
  3. Interroga le cartelle

    Per ogni indirizzo vengono indicati il provider e la cartella. Ripeti la richiesta finché lo stato non è più waiting.

    Richiesta

    # 3. poll for the folders
    curl -s 'https://email-spam-tester.com/api/v1/placement/<slug>'

    Risposta

    {
      "status": "complete",
      "received": 2,
      "total": 2,
      "results": [
        {"address": "<seed>", "provider": "gmail", "kind": "Gmail",
         "placement": "primary", "observed_at": "2026-10-31T12:04:11Z"},
        {"address": "<seed>", "provider": "gmail", "kind": "Google Workspace",
         "placement": "promotions", "observed_at": "2026-10-31T12:04:11Z"}
      ],
      "fleet": {
        "status": "finished",
        "results": [
          {"address": "<mailbox>", "provider": "yahoo", "available": true,
           "placement": "inbox", "coverage": "ok"},
          {"address": "<mailbox>", "provider": "outlook", "available": true,
           "placement": "spam", "coverage": "ok"}
        ]
      }
    }

Endpoint

An optional test using public GMass seed inboxes and available project test mailboxes, alone or alongside the email score. Explain to the sender that GMass receives their email and publishes its subject, sender name and placement before creating a test. Use all test mailboxes for non-confidential test messages only.

GET /api/v1/placement/availability

Returns providers: the provider identifiers of currently healthy, admitted project mailboxes. No addresses or credentials are exposed. This read does not create a test or contact GMass. Actual recipients are allocated at creation and may differ as availability or capacity changes.

POST /api/v1/placement

Send JSON {"public_results_accepted":true}. Returns HTTP 201 with slug, marker, results (the seed addresses), deadline and expires_at. Limit: 20 tests per IP per UTC day.

For one-send combined testing, first reserve an email score address and include its score_slug in the placement creation JSON. Repeated creation for that score returns the same placement test. Send the marked email to the score address, every returned seed and every available fleet.results address; keep the main /t/<score_slug> report link. Creating a link after the score address was used or expired returns HTTP 409.

GET /api/v1/placement/by-score/{score_slug}

Read and refresh the placement run attached to the main email test. The response has the same format and polling limits as the standalone endpoint below. HTTP 404 means placement was not included or its stored results have been removed.

GET /api/v1/placement/{slug}

Use poll_after_seconds (normally 60 seconds) while the page is open. Upstream errors trigger a shared cooldown. Add the marker to the subject and send through the sender's normal platform to every seed. Observations are saved for 30 days. Collection ends after 30 minutes or when all seeds have results.

status: waiting, complete or timed_out. Each result has an address, provider, kind, placement and observed_at. Placement is primary, promotions, inbox, updates, social, forums, spam, unknown, pending or not_observed. Missing results do not mean Spam; Promotions is an inbox category. provider_error indicates an upstream outage without discarding saved observations. HTTP 404 means unknown, 410 expired, 429 quota exhausted, and 503 no test inboxes available at creation.

The optional fleet object contains independently collected project mailbox results, with status observing, settling or finished. Refresh every 30 seconds until it finishes, even when Gmail has completed. Each fleet result includes address, provider, available, placement, category and coverage. Exclude unavailable addresses from new sends; retain their saved observations. Category data may be unavailable even when the physical folder is known.

If GMass is unavailable at creation but project mailboxes can be allocated, provider is fleet and the top-level seed results are empty. Use fleet.results; do not interpret an empty Gmail list as successful delivery. Existing runs never gain new recipient addresses silently.

Controllo dell'infrastruttura

Una richiesta GET controlla la configurazione della posta di un dominio senza inviare nulla, conserva il risultato e ti indica cosa è cambiato rispetto all'ultima esecuzione. Non serve alcuna chiave. In cron, la riga seguente termina con un codice diverso da zero quando il dominio non funziona o la sua configurazione è cambiata in modo rilevante.

Avvio rapido

  1. Esegui una GET

    Passa il dominio. ip aggiunge i tuoi indirizzi di invio e selector specifica i selettori DKIM da leggere.

    Richiesta

    curl -s 'https://email-spam-tester.com/api/v1/infra/check?domain=example.com&selector=mail&diff=true'
  2. Leggi il verdetto

    ok è la risposta per uno script e sections mostra quale parte ha dato errore.

    Risposta

    {
      "id": "ir_01JB8Y4T2M6K9QZ7H3V5N1XWDA",
      "domain": "example.com",
      "checked_at": "2026-10-31T12:00:00Z",
      "ok": false,
      "status": "fail",
      "score": 78,
      "coverage": {"answered": 7, "total": 8},
      "ips": [{"ip": "203.0.113.5", "sources": ["mx", "spf"], "managed": false}],
      "sections": {
        "dkim": {"status": "pass", "core": true, "findings": [], "data": {}},
        "ptr": {"status": "fail", "core": true, "findings": [], "data": {}}
      },
      "not_checked": [
        {"check": "dkim_signature", "reason": "needs_a_message"},
        {"check": "alignment", "reason": "needs_a_message"}
      ],
      "diff": {
        "baseline": {"id": "ir_01JB2...", "checked_at": "2026-10-24T12:00:00Z"},
        "first_run": false,
        "changed": true,
        "worsened": true,
        "status_from": "pass",
        "score_from": 100,
        "changes": [
          {"path": "dkim.key.mail.sha256", "section": "dkim", "kind": "removed",
           "severity": "critical", "effect": "worsened", "from": "9f2c...", "to": null}
        ],
        "not_compared": [
          {"path": "blocklist_ip.203.0.113.5.bl.spamcop.net.listed", "reason": "lookup_failed"}
        ]
      }
    }
  3. Inseriscilo in cron

    Con diff=true ogni esecuzione viene confrontata con la tua ultima esecuzione e jq trasforma la risposta in un codice di uscita.

    Richiesta

    # exits non-zero if the domain is broken or its setup changed
    curl -s 'https://email-spam-tester.com/api/v1/infra/check?domain=example.com&selector=mail&diff=true' \
      | jq -e '.ok and (.diff.changed | not)'
domainObbligatorio. Accetta ciò che accettano gli strumenti: un dominio, un URL, un indirizzo email.
ipIl tuo indirizzo di invio. Ripetilo per aggiungerne altri, fino a 6.
selectorUn selettore DKIM. Ripetilo per aggiungerne altri, fino a 10. Ogni selettore che passi deve esistere, altrimenti la sezione dkim non riesce.
heloIl nome che il tuo server fornisce in HELO, confrontato con il suo PTR.
accountLa persona per cui viene effettuata la richiesta. Obbligatorio con una chiave usata per più persone.
checksLe sezioni da eseguire, separate da virgole. Per impostazione predefinita, tutte.
difftrue confronta questa esecuzione con la tua ultima esecuzione del dominio.
since7d, 12h o una data ISO 8601. Confronta con la tua esecuzione più vicina a quel momento entro 12 ore, altrimenti con l'ultima precedente. Attiva diff.
baselineL'id di una delle tue esecuzioni con cui effettuare il confronto. Attiva diff.
freshtrue ignora la cache di 60 secondi.

Lettura della risposta

Un controllo completato restituisce 200 e il verdetto si trova nel corpo. status è lo stato peggiore delle sezioni obbligatorie: spf, dkim, dmarc, ptr, blocklist_ip, blocklist_domain, mx e smtp. unknown in una sezione obbligatoria conta come warn. ok è true quando status è pass o warn. score va da 0 a 100 sulle sezioni obbligatorie che hanno prodotto una risposta ed è null quando errori e valori unknown lasciano meno della metà del peso applicabile. mta_sts, tls_rpt, bimi, dnssec, dane, ns e registration vengono riportati e confrontati, ma non influiscono su ok o score.

Una sezione può essere pass, warn, fail, error (non è stato possibile controllarla), unknown (informazioni insufficienti) o skipped (non applicabile). skipped non influisce sul risultato e il motivo si trova in not_checked. dkim_signature e alignment sono sempre presenti, perché richiedono un messaggio reale.

Cosa cambia con ip e selector

PTR e le blocklist riguardano gli indirizzi, quindi un'esecuzione ne richiede alcuni. Usa i valori ip che fornisci. Se non ne fornisci, ne prende fino a quattro dagli host MX e dai termini ip4: e ip6: con un solo indirizzo nel record SPF radice. Gli indirizzi di un provider di posta noto vengono indicati come managed e non vengono controllati; se non resta alcun indirizzo, ptr e blocklist_ip restituiscono skipped. Un selector non può essere ricavato dal DNS, quindi un'esecuzione prova quello che fornisci, quelli trovati dalle tue esecuzioni precedenti e un elenco di nomi comuni. Non trovare nulla non dimostra nulla e dkim restituisce unknown. Se invii dal tuo server, fornisci entrambi.

Cosa è cambiato

Ogni voce in diff.changes ha un path, un kind (added, removed, changed), una severity (critical, warning, info) e un effect (worsened, improved, neutral). Solo critical e warning impostano diff.changed, quindi una chiave DKIM ruotata della stessa lunghezza, un nuovo indirizzo MX o un certificato rinnovato non causano il fallimento della riga cron. diff.worsened segue l'effetto di qualsiasi modifica. Alla prima esecuzione non c'è nulla con cui effettuare il confronto, e diff.first_run lo indica.

Una baseline è sempre una tua esecuzione, quindi il controllo del dominio da parte di qualcun altro tra due tue esecuzioni non nasconde nulla. Tutto ciò che non è stato possibile leggere questa volta viene inserito in diff.not_compared mantenendo il suo ultimo valore noto, il che significa che una modifica apportata durante un'interruzione compare non appena la ricerca torna a funzionare. Un'esecuzione con ip o selector diversi rimane nella stessa serie e anche ciò che non ha richiesto non viene confrontato.

Perché un controllo pianificato dovrebbe usare una chiave

Senza una chiave, la tua cronologia è associata a un hash con chiave del tuo indirizzo IP, quindi termina quando l'indirizzo cambia e le persone dietro lo stesso indirizzo la condividono: l'esecuzione di un collega sposta la tua baseline. Con una chiave API personale in Authorization: Bearer, la cronologia segue la chiave. Le esecuzioni con una chiave vengono conservate per 365 giorni e sono accessibili solo con quella chiave. Le esecuzioni senza chiave vengono conservate per 30 giorni e sono accessibili a chiunque disponga del loro id.

6 richieste al minuto e 50 al giorno per IP, oppure 30 e 500 per chiave. Oltre questi limiti, la risposta è 429 con Retry-After. Una richiesta identica entro 60 secondi proviene dalla cache, è contrassegnata con cached: true, non registra alcuna esecuzione e non viene conteggiata. La lettura delle esecuzioni memorizzate consente 120 richieste al minuto per client. 503 con Retry-After significa che sono in esecuzione troppi controlli oppure, durante la lettura delle esecuzioni memorizzate, che lo spazio di archiviazione non è disponibile. 401 indica una chiave errata. 422 include detail.code: invalid_domain, invalid_ip, invalid_selector, invalid_check, invalid_since, unknown_baseline o account_required.

Endpoint

GET/api/v1/infra/check

Esegue il controllo. I parametri sono nella tabella sopra.

GET/api/v1/infra/runs/{public_id}

Una singola esecuzione archiviata, completa. 404 se non esiste o appartiene a un'altra chiave.

GET/api/v1/infra/domains/{domain}/runs

Le tue esecuzioni per un dominio, dalla più recente: id, data e ora, stato, punteggio e numero di modifiche. Accetta limit (da 1 a 100, 30 per impostazione predefinita) e before, l'id di un'esecuzione.

GET/api/v1/infra/diff

Lo stesso confronto tra due esecuzioni archiviate, ?from=<id>&to=<id>. Devi avere accesso a entrambe.

GET/api/v1/infra/checks

Ogni sezione con il relativo peso, la versione del punteggio e i limiti.

Controlli singoli

Ogni chiamata risponde a una domanda e non conserva alcuna cronologia. Uno strumento esegue autonomamente una parte del controllo dell'infrastruttura, ad eccezione dello strumento per le intestazioni, che legge un messaggio che hai già ricevuto.

Avvio rapido

  1. Scegli un controllo

    Scegli lo strumento dall'elenco seguente e fornisci il dominio, l'indirizzo o l'IP richiesto.

    Richiesta

    curl -s 'https://email-spam-tester.com/api/v1/tools/spf?domain=example.com'
  2. Leggi lo stato e i risultati

    Ogni strumento restituisce uno stato e i relativi risultati. I campi successivi dipendono dallo strumento.

    Risposta

    {
      "tool": "spf",
      "query": {"domain": "example.com"},
      "checked_at": "2026-10-31T12:00:00Z",
      "duration_ms": 412,
      "status": "fail",
      "findings": [
        {"code": "spf.too_many_lookups", "level": "fail",
         "params": {"limit": 10, "count": 12},
         "message": "RFC 7208 §4.6.4 allows at most 10 DNS lookups, and this record needs 12, so receivers return permerror."}
      ],
      "record": "v=spf1 include:_spf.example.net ~all",
      "lookups": {"count": 12, "limit": 10, "void": 0}
    }

Endpoint

Tutti rispondono con 200, uno stato e un elenco di risultati, ciascuno con un codice e i relativi parametri. Lo stato è pass, warn, fail o error, e uno strumento condiviso con il controllo dell'infrastruttura può anche rispondere unknown o skipped. Una ricerca scaduta o un elenco che ha rifiutato la richiesta non conta mai come pass. 30 richieste al minuto e 300 al giorno per IP complessivamente tra gli strumenti; oltre questi limiti la risposta è 429 con Retry-After.

GET/api/v1/tools/spf

Il record SPF di un dominio: la sua sintassi, ogni include e redirect seguito e il numero di ricerche DNS che l'intero albero consuma rispetto al limite di dieci. Specificare ?domain=example.com.

GET/api/v1/tools/dmarc

Il record DMARC di un dominio, o del suo dominio organizzativo quando non ne ha uno: i tag, la policy e se ogni indirizzo esterno per i report ha accettato di riceverli. Specificare ?domain=example.com.

GET/api/v1/tools/dkim

La chiave DKIM pubblicata per un selettore: se esiste e può essere decodificata, il suo tipo e la sua dimensione e i flag di revoca e test. Specificare ?domain=example.com&selector=s1.

GET/api/v1/tools/blocklist

Un indirizzo IPv4, un indirizzo IPv6 o un dominio verificato rispetto alle blocklist DNS utilizzate dal report, con la risposta di ogni lista. Specificare ?target=203.0.113.5.

GET/api/v1/tools/mx

I record MX di un dominio nell'ordine in cui i mittenti li provano, con gli indirizzi IPv4 e IPv6 di ogni host. Vengono segnalati un MX nullo, un dominio senza MX, gli host che sono indirizzi IP o CNAME e gli host che non si risolvono, così come i record MTA-STS e TLS-RPT. Passa ?domain=example.com.

GET/api/v1/tools/bimi

La configurazione BIMI di un dominio in quattro passaggi: la policy DMARC richiesta da BIMI, il record in default._bimi, il logo SVG verificato rispetto al profilo Tiny PS e il certificato del marchio con tipo, domini e scadenza. Passa ?domain=example.com e &selector= per un selettore diverso da default.

GET/api/v1/tools/ptr

I record PTR di un indirizzo e se uno di questi nomi si risolve nuovamente nell'indirizzo. Una ricerca non riuscita restituisce lo stato error; un record mancante restituisce lo stato fail. Passa ?ip=8.8.8.8.

GET/api/v1/tools/mta-sts

Il record MTA-STS di un dominio e il file di policy a cui punta: la modalità, gli host elencati e qualsiasi host MX escluso dalla policy. Passa ?domain=example.com.

GET/api/v1/tools/tls-rpt

Il record TLS-RPT di un dominio e gli indirizzi che ricevono i relativi report. Passa ?domain=example.com.

GET/api/v1/tools/dnssec

Se la zona di un dominio è firmata, non firmata o non valida, in base ai suoi record DNSKEY e DS. Una firma non valida viene distinta da un'interruzione del resolver. Passa ?domain=example.com.

GET/api/v1/tools/dane

I record TLSA degli host MX, confrontati con il certificato presentato da un host quando è stato possibile leggere tale certificato. Passa ?domain=example.com.

GET/api/v1/tools/smtp

STARTTLS e il certificato sui primi due host MX: versione TLS, autorità emittente, data di scadenza e validità della catena e del nome. Ci connettiamo solo agli host appartenenti al dominio che hai richiesto ed escludiamo i provider di posta, e un risultato per indirizzo viene condiviso per 6 ore. Non viene inviata alcuna email. Passa ?domain=example.com.

GET/api/v1/tools/ns

I name server di un dominio e se la relativa zona contiene un record SOA. Un solo name server genera un avviso. Passa ?domain=example.com.

GET/api/v1/tools/registration

Quando scade la registrazione di un dominio, in base a RDAP. Se rimangono meno di 30 giorni viene generato un avviso. Una zona senza un servizio RDAP restituisce skipped. Passa ?domain=example.com.

POST/api/v1/tools/header

Le intestazioni di un messaggio ricevuto, inviate come JSON {"headers": "..."} o come text/plain: il percorso hop per hop con ritardi, TLS e deriva dell'orologio, l'Authentication-Results del destinatario, l'allineamento dei domini From, DKIM d= e Return-Path e le intestazioni DKIM, ARC, di annullamento dell'iscrizione e dei filtri antispam. Tutto ciò che segue la prima riga vuota viene eliminato senza essere letto. Le intestazioni vengono elaborate in memoria e non vengono archiviate, memorizzate nella cache o registrate nei log.

Controlla il dominio ogni notte.
Testa l'email prima che venga inviata.

Condiviso da ogni prodotto

Accesso, chiavi, formato del report, stati, errori, oltre a OpenAPI e llms.txt per le macchine.

Autenticazione

Non ce n'è. Nessuna chiave da richiedere, nessuna intestazione da impostare, nessun account da creare. Lo slug restituito è la capability: chiunque lo possieda può leggere quel report e nessun altro può indovinarlo.

Questo significa anche che uno slug va trattato come una password. Un report mostra l'oggetto, il mittente, l'indirizzo per i rimbalzi e il sorgente completo del messaggio a chiunque possieda il link.

Chiavi API personali

Everything above works without a key. A key is for automation platforms such as Zapier, where every user's calls come from the platform's servers and per-IP limits would be shared by all of them. With a key, limits count per key (50 tests a day, 3 with placement, 5 permanent mailboxes), the key's tests form a history, and the key can keep permanent mailboxes whose reports only it can read. Send the key as Authorization: Bearer est_live_… on any call on this page. The routes below also take account, a short name of your choosing ([A-Za-z0-9_-], up to 64 characters) that keeps separate lists under one key. GET /api/v1/installations/tests requires it; pass the same one on POST /api/v1/inbox so the test shows up there. The Zapier integration uses zapier.

POST /api/v1/keys

Send JSON {"email":"you@example.com"}. Returns HTTP 201 with key and email. The key is shown once; only its hash is kept. Asking again gives a new key and leaves the earlier ones working. Limit: 5 keys per IP per UTC day. The form on /zapier/ calls this.

GET /api/v1/keys/me

Returns email, key_prefix and created_at of the key in the header, or HTTP 401. Use it to check a key.

GET /api/v1/installations/tests

The key's tests, newest first: ?account=…&limit=50 (up to 100), and before=<slug> for the next page. Each item has slug, created_at, analysis_status (waiting or expired before an email arrived), score_ours, score_compat, placement and changes, the checks that moved since the previous test of the same sending domain. Read the full report at /api/v1/tests/{slug}.

POST /api/v1/installations/mailboxes

Send JSON {"domain":"example.com","account":"…"}. Returns the permanent mailbox of that sending domain: id, address, domain, state, daily_cap and created. HTTP 201 when it is new, 200 when it already existed, 409 when the key keeps as many mailboxes as it may. Subscribe the address to a newsletter or a sequence and every email that arrives is checked. GET on the same path with ?account=… lists them, and DELETE /api/v1/installations/mailboxes/{mailbox_id} stops one.

GET /api/v1/installations/mailboxes/{mailbox_id}/letters

The emails that arrived, oldest first, paged with after_id and next_after_id. settled=true ends the page before the first email still being checked, so paging never skips one. newest=true turns the order round, for a quick look at the latest; settled does nothing with it. Each has test_id, slug, received_at, analysis_status, score_ours, score_compat, subject, from_addr and kind.

GET /api/v1/installations/letters/{slug}

The report of one email in a permanent mailbox, the same JSON as /api/v1/tests/{slug} with report_url null: there is no public page for it. HTTP 410 once the report has expired.

Lettura del report

I campi che contengono la risposta, nell'ordine in cui probabilmente servono.

score_oursDa 0 a 100. Il nostro modello. L'autenticazione e l'infrastruttura hanno il peso maggiore, perché determinano la consegna prima che un filtro legga una parola del testo.
score_compatDa 0 a 10. Riproduce il valore in stile SpamAssassin che gli utenti già confrontano, in modo che il report sia comparabile con quanto rilevato altrove.
subscoresLa stessa scala da 0 a 100 per sezione: auth, infra_spam, content, compliance.
checks[]Tutti e 42, ciascuno con uno stato, un esito di una riga, le evidenze su cui è stata basata la decisione e il relativo costo sui due punteggi.
checks[].citationsDa dove proviene il riscontro: la sezione della RFC, citata testualmente, e la pagina in cui Google dichiara il proprio requisito. Selezionati manualmente anziché generati, quindi sono affidabili.
fixes[]Cosa modificare, in ordine, con i punti attribuiti a ciascuna modifica. I guadagni sono calcolati ricalcolando il punteggio del report, non stimati.
completeFalso quando non è stato possibile eseguire un controllo. Un elemento non controllato non è mai un esito positivo, quindi considera il punteggio ottimistico finché non è vero.
report_urlLa pagina leggibile da una persona. Fornisci quella a una persona anziché un muro di JSON.

Stati

Un controllo può trovarsi in uno di cinque stati, e la differenza tra due di essi è più importante di quanto sembri.

passIl controllo è stato eseguito e non ha rilevato problemi.
warnDa correggere. Costa punti.
failComprometterà la consegna. Costa più punti.
ignoratoNon applicabile. Nessun allegato da analizzare, nessuna parte HTML da valutare. Non è un esito positivo.
erroreNon è stato possibile determinarlo. Escluso dal punteggio e contrassegnato, anziché conteggiato come esito positivo.

analysis_status assume i valori received, analyzing, checks_ready, failed. ai_status assume i valori pending, running, ready, fallback, error. Il report deterministico è definitivo a checks_ready; ai_status aggiunge sempre e solo il piano.

Cosa può essere restituito

202L'indirizzo è riservato e non è arrivato alcun messaggio. Il corpo contiene l'indirizzo, la scadenza e la lingua, quindi un chiamante che non ha creato la prenotazione può comunque mostrarla.
404Nessuno slug corrispondente. Non è mai esistito oppure la prenotazione è stata dimenticata.
410L'indirizzo è scaduto prima dell'arrivo di un messaggio.
409Hai tentato di cambiare la lingua dopo che il messaggio era già arrivato.
429Il limite di test gratuiti per il tuo indirizzo. Al momento non esiste alcun limite per persona su questo servizio; se ne verrà mai impostato uno, il corpo indicherà quando verrà reimpostato.

Quattro cose da sapere

Un messaggio per indirizzo

Il secondo viene rifiutato. Il report precedente rimane intatto, ed è proprio questo lo scopo.

Un'ora per usarlo

L'indirizzo scade; il report no. I link ai report sono permanenti, quindi uno incollato in un ticket continua a funzionare.

Invia dalla piattaforma

Testare una campagna da un account personale misura quell'account. Quasi tutto nella sezione sull'autenticazione riguarda l'infrastruttura di invio, non il testo.

Ripeti il test dopo la correzione

I miglioramenti previsti vengono calcolati una correzione alla volta e non si sommano. Il secondo report fornisce il valore reale.

Per le macchine

GET/api/health

Liveness. Nessuna autenticazione, nessun effetto collaterale.

Provane prima uno manualmente

Richiede circa un minuto e mostra esattamente ciò che descrive il JSON.

Ottieni un indirizzo di test

Sandbox.

Ogni endpoint, con un pulsante che lo esegue sul servizio attivo. Qui non serve alcuna chiave, quindi una richiesta inviata da questa pagina è reale: riserva un indirizzo reale e viene conteggiata.

Provalo nella sandbox