Free Email Spam Tester Infra checks API
The Infra checks API from Free Email Spam Tester — 5 operation(s) for infra checks.
The Infra checks API from Free Email Spam Tester — 5 operation(s) for infra checks.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/email-spam-tester-com:email-spam-tester-com-infra-checks-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Email Spam Tester Infra checks API
description: 'Test an email before you send it to anybody.
The loop is three calls. Ask for an address, send the message you were about to
send your list to that address, then read the report. No key, no account, no
limit per person on the first 100,000 reports.
curl -X POST https://email-spam-tester.com/api/v1/inbox
# send your message to the address it returns, then:
curl https://email-spam-tester.com/api/v1/tests/
The address accepts exactly one message and expires after an hour. The report
link is permanent and carries `report_url` inside the JSON, so a forwarded
report still says where it came from.
**Poll `/status`, not `/`.** The full report is several thousand lines of JSON
and the analysis takes a few seconds; the status endpoint is the cheap way to
find out whether it is worth fetching yet. `analysis_status` reaches
`checks_ready` first and the AI plan lands a minute or so later under
`ai_status`, so a caller that only wants the checks does not have to wait for
the plan.
**Agents:** there is an MCP server at `/mcp` with the same capability and a
blocking wait, which is a better fit than polling from a model.
Every finding carries `citations`: the section of the RFC it comes from, quoted,
and the page where Google states its own requirement. Those are curated by hand
rather than generated, so they can be relied on.'
contact:
name: Email Spam Tester
url: https://email-spam-tester.com/
version: 1.0.0
tags:
- name: Infra checks
paths:
/api/v1/infra/check:
get:
tags:
- Infra checks
summary: Check a domain's mail infrastructure
description: SPF, DKIM, DMARC, PTR, blocklists, MX and STARTTLS, with MTA-STS, TLS-RPT, BIMI, DNSSEC, DANE, name servers and the registration as advice, all without a message. With `diff=true` the answer says what changed since your last run. A completed check is 200; `ok`, `status` and `not_checked` carry the verdict.
operationId: check_api_v1_infra_check_get
parameters:
- name: domain
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: Domain
- name: ip
in: query
required: false
schema:
type: array
items:
type: string
description: Sending address, up to 6.
default: []
title: Ip
description: Sending address, up to 6.
- name: selector
in: query
required: false
schema:
type: array
items:
type: string
description: Selector, up to 10.
default: []
title: Selector
description: Selector, up to 10.
- name: helo
in: query
required: false
schema:
anyOf:
- type: string
maxLength: 255
- type: 'null'
title: Helo
- name: account
in: query
required: false
schema:
anyOf:
- type: string
maxLength: 64
- type: 'null'
title: Account
- name: checks
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: Sections, comma separated.
title: Checks
description: Sections, comma separated.
- name: diff
in: query
required: false
schema:
type: boolean
default: false
title: Diff
- name: baseline
in: query
required: false
schema:
anyOf:
- type: string
maxLength: 64
- type: 'null'
title: Baseline
- name: since
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: 7d or an ISO 8601 date.
title: Since
description: 7d or an ISO 8601 date.
- name: fresh
in: query
required: false
schema:
type: boolean
default: false
title: Fresh
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/InfraOut'
'422':
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorOut'
description: Unprocessable Entity
'429':
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorOut'
description: Too Many Requests
'503':
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorOut'
description: Service Unavailable
/api/v1/infra/runs/{public_id}:
get:
tags:
- Infra checks
summary: One stored run
description: A run made with a key opens only with that key; otherwise 404.
operationId: read_run_api_v1_infra_runs__public_id__get
parameters:
- name: public_id
in: path
required: true
schema:
type: string
title: Public Id
- name: account
in: query
required: false
schema:
anyOf:
- type: string
maxLength: 64
- type: 'null'
title: Account
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/InfraOut'
'404':
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorOut'
description: Not Found
'429':
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorOut'
description: Too Many Requests
'503':
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorOut'
description: Service Unavailable
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/api/v1/infra/domains/{domain}/runs:
get:
tags:
- Infra checks
summary: Your runs of a domain, newest first
description: 'Runs of the caller only: a key, or the hash of the address.'
operationId: list_runs_api_v1_infra_domains__domain__runs_get
parameters:
- name: domain
in: path
required: true
schema:
type: string
title: Domain
- name: limit
in: query
required: false
schema:
type: integer
maximum: 100
minimum: 1
default: 30
title: Limit
- name: before
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: Before
- name: account
in: query
required: false
schema:
anyOf:
- type: string
maxLength: 64
- type: 'null'
title: Account
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/RunsOut'
'422':
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorOut'
description: Unprocessable Entity
'429':
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorOut'
description: Too Many Requests
'503':
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorOut'
description: Service Unavailable
/api/v1/infra/diff:
get:
tags:
- Infra checks
summary: What changed between two runs
description: Needs access to both runs; otherwise 404.
operationId: diff_runs_api_v1_infra_diff_get
parameters:
- name: from
in: query
required: true
schema:
type: string
title: From
- name: to
in: query
required: true
schema:
type: string
title: To
- name: account
in: query
required: false
schema:
anyOf:
- type: string
maxLength: 64
- type: 'null'
title: Account
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/InfraDiff'
'404':
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorOut'
description: Not Found
'429':
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorOut'
description: Too Many Requests
'503':
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorOut'
description: Service Unavailable
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/api/v1/infra/checks:
get:
tags:
- Infra checks
summary: The sections, their weights and the limits
description: 'Static: what /infra/check runs and what it may be asked for.'
operationId: catalogue_api_v1_infra_checks_get
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/ChecksOut'
components:
schemas:
InfraIp:
properties:
ip:
type: string
title: Ip
sources:
items:
type: string
type: array
title: Sources
managed:
type: boolean
title: Managed
description: Run by a provider, so not checked.
type: object
required:
- ip
- sources
- managed
title: InfraIp
NotCompared:
properties:
path:
type: string
title: Path
reason:
type: string
enum:
- lookup_failed
- not_requested
title: Reason
type: object
required:
- path
- reason
title: NotCompared
ValidationError:
properties:
loc:
items:
anyOf:
- type: string
- type: integer
type: array
title: Location
msg:
type: string
title: Message
type:
type: string
title: Error Type
input:
title: Input
ctx:
type: object
title: Context
type: object
required:
- loc
- msg
- type
title: ValidationError
DiffBaseline:
properties:
id:
type: string
title: Id
checked_at:
type: string
title: Checked At
type: object
required:
- id
- checked_at
title: DiffBaseline
HTTPValidationError:
properties:
detail:
items:
$ref: '#/components/schemas/ValidationError'
type: array
title: Detail
type: object
title: HTTPValidationError
InfraOut:
properties:
id:
anyOf:
- type: string
- type: 'null'
title: Id
description: Null when the run was not stored.
domain:
type: string
title: Domain
checked_at:
type: string
title: Checked At
duration_ms:
type: integer
title: Duration Ms
schema_version:
type: integer
title: Schema Version
score_version:
type: integer
title: Score Version
cached:
type: boolean
title: Cached
stored:
type: boolean
title: Stored
ok:
type: boolean
title: Ok
status:
type: string
title: Status
score:
anyOf:
- type: integer
- type: 'null'
title: Score
coverage:
additionalProperties:
type: integer
type: object
title: Coverage
summary:
additionalProperties:
type: integer
type: object
title: Summary
ips:
items:
$ref: '#/components/schemas/InfraIp'
type: array
title: Ips
sections:
additionalProperties:
$ref: '#/components/schemas/InfraSection'
type: object
title: Sections
not_checked:
items:
$ref: '#/components/schemas/NotChecked'
type: array
title: Not Checked
diff:
anyOf:
- $ref: '#/components/schemas/InfraDiff'
- type: 'null'
description: Null unless diff, since or baseline asked for it.
type: object
required:
- id
- domain
- checked_at
- duration_ms
- schema_version
- score_version
- cached
- stored
- ok
- status
- score
- coverage
- summary
- ips
- sections
- not_checked
- diff
title: InfraOut
ChecksOut:
properties:
sections:
items:
$ref: '#/components/schemas/CheckRow'
type: array
title: Sections
score_version:
type: integer
title: Score Version
schema_version:
type: integer
title: Schema Version
limits:
additionalProperties:
additionalProperties:
type: integer
type: object
type: object
title: Limits
type: object
required:
- sections
- score_version
- schema_version
- limits
title: ChecksOut
NotChecked:
properties:
check:
type: string
title: Check
reason:
type: string
title: Reason
type: object
required:
- check
- reason
title: NotChecked
ToolErrorOut:
properties:
detail:
$ref: '#/components/schemas/ToolError'
type: object
required:
- detail
title: ToolErrorOut
InfraDiff:
properties:
baseline:
anyOf:
- $ref: '#/components/schemas/DiffBaseline'
- type: 'null'
first_run:
type: boolean
title: First Run
changed:
type: boolean
title: Changed
description: A change of severity critical or warning.
worsened:
type: boolean
title: Worsened
status_from:
anyOf:
- type: string
- type: 'null'
title: Status From
score_from:
anyOf:
- type: integer
- type: 'null'
title: Score From
changes:
items:
$ref: '#/components/schemas/DiffChange'
type: array
title: Changes
not_compared:
items:
$ref: '#/components/schemas/NotCompared'
type: array
title: Not Compared
reason:
anyOf:
- type: string
- type: 'null'
title: Reason
description: storage_unavailable when nothing could be read or kept.
type: object
required:
- baseline
- first_run
- changed
- worsened
- status_from
- score_from
- changes
- not_compared
title: InfraDiff
CheckRow:
properties:
name:
type: string
title: Name
weight:
type: integer
title: Weight
description: Share of the score; 0 means advisory.
core:
type: boolean
title: Core
type: object
required:
- name
- weight
- core
title: CheckRow
InfraSection:
properties:
status:
type: string
title: Status
description: pass, warn, fail, error, unknown or skipped.
core:
type: boolean
title: Core
description: Counts toward status, ok and score.
findings:
items:
$ref: '#/components/schemas/Finding'
type: array
title: Findings
data:
additionalProperties: true
type: object
title: Data
type: object
required:
- status
- core
- findings
- data
title: InfraSection
RunsOut:
properties:
runs:
items:
$ref: '#/components/schemas/RunRow'
type: array
title: Runs
type: object
required:
- runs
title: RunsOut
DiffChange:
properties:
path:
type: string
title: Path
description: dkim.key.mail.sha256, dmarc.policy, mx.hosts and so on.
section:
type: string
title: Section
kind:
type: string
enum:
- added
- removed
- changed
title: Kind
severity:
type: string
enum:
- critical
- warning
- info
title: Severity
effect:
type: string
enum:
- worsened
- improved
- neutral
title: Effect
from:
title: From
to:
title: To
type: object
required:
- path
- section
- kind
- severity
- effect
- from
- to
title: DiffChange
RunRow:
properties:
id:
type: string
title: Id
checked_at:
type: string
title: Checked At
status:
type: string
title: Status
score:
anyOf:
- type: integer
- type: 'null'
title: Score
changes_count:
anyOf:
- type: integer
- type: 'null'
title: Changes Count
type: object
required:
- id
- checked_at
- status
- score
- changes_count
title: RunRow
Finding:
properties:
code:
type: string
title: Code
description: Stable identifier, e.g. spf.too_many_lookups. The English template for every code is in /i18n/tools/findings.en.json on the website.
level:
type: string
enum:
- pass
- info
- warn
- fail
- error
title: Level
params:
additionalProperties: true
type: object
title: Params
description: Values the message is built from.
message:
type: string
title: Message
description: The English sentence, params filled in.
type: object
required:
- code
- level
- params
- message
title: Finding
ToolError:
properties:
code:
type: string
enum:
- invalid_domain
- invalid_selector
- invalid_target
- invalid_ip
- invalid_check
- invalid_since
- unknown_baseline
- account_required
- invalid_headers
- rate_limited
- busy
- storage_unavailable
title: Code
message:
type: string
title: Message
type: object
required:
- code
- message
title: ToolError