Free Email Spam Tester Tests API

The Tests API from Free Email Spam Tester — 4 operation(s) for tests.

GitHub OpenAPI

Operations 4

PUT /api/v1/tests/{slug}/locale Set Locale #
GET /api/v1/tests/{slug}/status Test Status #
GET /api/v1/tests/{slug}/message Message #
GET /api/v1/tests/{slug} Report #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • 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.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/email-spam-tester-com:email-spam-tester-com-tests-api"
All apis
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.

Get an API 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 Specification

email-spam-tester-com-tests-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Email Spam Tester Tests 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: Tests
paths:
  /api/v1/tests/{slug}/locale:
    put:
      summary: Set Locale
      description: 'Change which language the report and the AI plan will be written in.


        The language is fixed when the address is handed out, because the SMTP

        connection that arrives ten minutes later carries no hint of who is

        waiting for it. That leaves one gap: somebody reserves an address, then

        switches the page to their own language before sending. Without this they

        would read a German page and get an English plan.


        Only while the reservation is unused. Once the mail has arrived the

        analysis is either running or done, and rewriting the language then would

        mean re-running it — a different operation, and one nobody asked for.


        The slug is the capability, as everywhere else here: whoever holds the

        address holds the test. There is nothing to leak — a wrong guess sets the

        language of a report the guesser cannot read.'
      operationId: set_locale_api_v1_tests__slug__locale_put
      parameters:
      - name: slug
        in: path
        required: true
        schema:
          type: string
          title: Slug
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LocaleIn'
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Tests
  /api/v1/tests/{slug}/status:
    get:
      summary: Test Status
      description: 'Where the analysis is. With `wait`, hold the request until it gets there.


        A panel plugin would otherwise poll every couple of seconds for a minute or

        five, from thousands of servers. `until=checks` returns once the checks are

        in; `until=plan` waits for the AI plan as well. Past `wait` seconds it

        answers with whatever there is, the same as without it.'
      operationId: test_status_api_v1_tests__slug__status_get
      parameters:
      - name: slug
        in: path
        required: true
        schema:
          type: string
          title: Slug
      - name: wait
        in: query
        required: false
        schema:
          type: integer
          maximum: 50
          minimum: 0
          default: 0
          title: Wait
      - name: until
        in: query
        required: false
        schema:
          enum:
          - checks
          - plan
          type: string
          default: checks
          title: Until
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatusOut'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Tests
  /api/v1/tests/{slug}/message:
    get:
      summary: Message
      description: 'The message itself: headers, both bodies, and the source verbatim.


        Separate from the report rather than a field on it, because the report is

        polled every two seconds while the analysis runs and a megabyte of source

        on every poll would be paid for by every user to serve the few who open the

        panel. This is fetched once, when they do.'
      operationId: message_api_v1_tests__slug__message_get
      parameters:
      - name: slug
        in: path
        required: true
        schema:
          type: string
          title: Slug
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageViewOut'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Tests
  /api/v1/tests/{slug}:
    get:
      summary: Report
      operationId: report_api_v1_tests__slug__get
      parameters:
      - name: slug
        in: path
        required: true
        schema:
          type: string
          title: Slug
      - name: lang
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Lang
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportOut'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Tests
components:
  schemas:
    AttachmentOut:
      properties:
        filename:
          anyOf:
          - type: string
          - type: 'null'
          title: Filename
        content_type:
          type: string
          title: Content Type
        size_bytes:
          type: integer
          title: Size Bytes
        inline:
          type: boolean
          title: Inline
      type: object
      required:
      - filename
      - content_type
      - size_bytes
      - inline
      title: AttachmentOut
    LocaleIn:
      properties:
        lang:
          type: string
          title: Lang
      type: object
      required:
      - lang
      title: LocaleIn
      description: 'Which language the reader is on now.


        Sent when somebody switches language on a reservation they have not used

        yet. Not validated to a fixed set here: locales.normalise falls back to the

        base language and then to English, so an unknown tag is a page in English

        rather than a 422 the visitor cannot act on.'
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    MessageOut:
      properties:
        subject:
          type: string
          title: Subject
        from_addr:
          anyOf:
          - type: string
          - type: 'null'
          title: From Addr
        bounce_address:
          anyOf:
          - type: string
          - type: 'null'
          title: Bounce Address
        size_bytes:
          type: integer
          title: Size Bytes
        has_html:
          type: boolean
          title: Has Html
        has_text:
          type: boolean
          title: Has Text
        forged_headers:
          additionalProperties: true
          type: object
          title: Forged Headers
        kind:
          anyOf:
          - type: string
          - type: 'null'
          title: Kind
      type: object
      required:
      - subject
      - from_addr
      - bounce_address
      - size_bytes
      - has_html
      - has_text
      - forged_headers
      title: MessageOut
    ReportOut:
      properties:
        report_url:
          type: string
          title: Report Url
          default: ''
        generated_by:
          type: string
          title: Generated By
          default: Email Spam Tester (https://email-spam-tester.com)
        slug:
          type: string
          title: Slug
        analysis_status:
          type: string
          title: Analysis Status
        ai_status:
          type: string
          title: Ai Status
        score_compat:
          anyOf:
          - type: number
          - type: 'null'
          title: Score Compat
        score_ours:
          anyOf:
          - type: number
          - type: 'null'
          title: Score Ours
        subscores:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Subscores
        scoring_version:
          anyOf:
          - type: string
          - type: 'null'
          title: Scoring Version
        complete:
          type: boolean
          title: Complete
        errored_checks:
          items:
            type: string
          type: array
          title: Errored Checks
        ai_verdict:
          anyOf:
          - type: string
          - type: 'null'
          title: Ai Verdict
        ai_confidence:
          anyOf:
          - type: string
          - type: 'null'
          title: Ai Confidence
        received_at:
          type: string
          format: date-time
          title: Received At
        checks_ready_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Checks Ready At
        message:
          anyOf:
          - $ref: '#/components/schemas/MessageOut'
          - type: 'null'
        panel:
          items:
            $ref: '#/components/schemas/EngineOut'
          type: array
          title: Panel
        checks:
          items:
            $ref: '#/components/schemas/CheckOut'
          type: array
          title: Checks
        fixes:
          items:
            $ref: '#/components/schemas/FixOut'
          type: array
          title: Fixes
        translating:
          type: boolean
          title: Translating
          default: false
      type: object
      required:
      - slug
      - analysis_status
      - ai_status
      - score_compat
      - score_ours
      - subscores
      - scoring_version
      - complete
      - errored_checks
      - ai_verdict
      - ai_confidence
      - received_at
      - checks_ready_at
      - message
      - panel
      - checks
      - fixes
      title: ReportOut
    mailtester__api__schemas__HeaderOut:
      properties:
        name:
          type: string
          title: Name
        value:
          type: string
          title: Value
        forged:
          type: boolean
          title: Forged
      type: object
      required:
      - name
      - value
      - forged
      title: HeaderOut
    StatusOut:
      properties:
        slug:
          type: string
          title: Slug
        analysis_status:
          type: string
          title: Analysis Status
        ai_status:
          type: string
          title: Ai Status
        checks_done:
          type: integer
          title: Checks Done
        checks_total:
          type: integer
          title: Checks Total
      type: object
      required:
      - slug
      - analysis_status
      - ai_status
      - checks_done
      - checks_total
      title: StatusOut
    CheckOut:
      properties:
        id:
          type: string
          title: Id
        category:
          type: string
          title: Category
        status:
          type: string
          title: Status
        title:
          type: string
          title: Title
        summary:
          type: string
          title: Summary
        summary_localised:
          anyOf:
          - type: string
          - type: 'null'
          title: Summary Localised
        weight_compat:
          type: number
          title: Weight Compat
        weight_ours:
          type: number
          title: Weight Ours
        evidence:
          additionalProperties: true
          type: object
          title: Evidence
        citations:
          additionalProperties: true
          type: object
          title: Citations
          default: {}
      type: object
      required:
      - id
      - category
      - status
      - title
      - summary
      - weight_compat
      - weight_ours
      - evidence
      title: CheckOut
    FixOut:
      properties:
        id:
          type: string
          title: Id
        fix:
          additionalProperties: true
          type: object
          title: Fix
        gain_compat:
          type: number
          title: Gain Compat
        gain_ours:
          type: number
          title: Gain Ours
        source:
          type: string
          title: Source
      type: object
      required:
      - id
      - fix
      - gain_compat
      - gain_ours
      - source
      title: FixOut
    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
    MessageViewOut:
      properties:
        available:
          type: boolean
          title: Available
        unavailable_reason:
          anyOf:
          - type: string
          - type: 'null'
          title: Unavailable Reason
        size_bytes:
          type: integer
          title: Size Bytes
        headers:
          items:
            $ref: '#/components/schemas/mailtester__api__schemas__HeaderOut'
          type: array
          title: Headers
        text:
          anyOf:
          - type: string
          - type: 'null'
          title: Text
        text_truncated:
          type: boolean
          title: Text Truncated
        html:
          anyOf:
          - type: string
          - type: 'null'
          title: Html
        html_truncated:
          type: boolean
          title: Html Truncated
        attachments:
          items:
            $ref: '#/components/schemas/AttachmentOut'
          type: array
          title: Attachments
        source:
          anyOf:
          - type: string
          - type: 'null'
          title: Source
        source_truncated:
          type: boolean
          title: Source Truncated
      type: object
      required:
      - available
      - unavailable_reason
      - size_bytes
      - headers
      - text
      - text_truncated
      - html
      - html_truncated
      - attachments
      - source
      - source_truncated
      title: MessageViewOut
      description: The raw message, for reading. Absent once its retention window closes.
    EngineOut:
      properties:
        id:
          type: string
          title: Id
        title:
          type: string
          title: Title
        status:
          type: string
          title: Status
        summary:
          type: string
          title: Summary
        evidence:
          additionalProperties: true
          type: object
          title: Evidence
        scores:
          type: boolean
          title: Scores
      type: object
      required:
      - id
      - title
      - status
      - summary
      - evidence
      - scores
      title: EngineOut