Skip to content

Getting started · Beginner · 5 min read

Test your integration with free test email addresses

Use SimpleCold's test addresses to exercise every result path in development and CI without spending credits. Includes Jest and pytest examples.

Jun 18, 2026 · SimpleCold team

A list of free test addresses and the fixed result each returns, such as test7@acceptall.com for accept_all and test5@notfound.com for mailbox_not_found

Real verifications cost credits and depend on mail servers you don't control. That makes them a poor fit for unit tests, CI runs and the hundred manual clicks you make while building a form. SimpleCold has a set of test addresses for this. They return the same result every time, they answer instantly, and they don't use credits on the single and batch endpoints. Bulk uploads are different, as covered further down.

This guide lists the addresses, shows what each one returns, and builds small test suites in Node.js and Python that cover every branch of your result handling.

The test addresses

Six addresses always return a deliverable result:

[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]

The rest each return one specific outcome, so you can test each branch of your code:

AddressstatuscategoryfailType
[email protected]mailbox_founddeliverablenone
[email protected]no_responseriskytemporary
[email protected]server_errorundeliverabletemporary
[email protected]server_errorundeliverabletemporary
[email protected]mailbox_not_foundundeliverablepermanent
[email protected]blocked_by_serverriskytemporary
[email protected]accept_allriskynone
[email protected]mailbox_unconfirmedriskynone
[email protected]disposableriskynone

Matching is case-insensitive, so [email protected] behaves the same as the lowercase form.

Watch the domains. [email protected] is deliverable, while [email protected] is a missing mailbox. The local part repeats across domains, so copy the full address.

A quick check with cURL

curl -s -G https://simplecold.com/api/v1/api-validation/single \
  --data-urlencode "[email protected]" \
  -H "Authorization: Bearer $SIMPLECOLD_API_KEY"
{
  "code": "SUCCESS",
  "message": "Successfully performed operation.",
  "payload": {
    "email": "[email protected]",
    "domain": "acceptall.com",
    "status": "accept_all",
    "statusMessage": "The domain accepts mail for any address, so this mailbox can't be confirmed.",
    "category": "risky",
    "failType": "none",
    "mxLocation": "US",
    "siteLocation": "US",
    "siteLanguage": "EN",
    "suggestion": null
  },
  "requestId": "..."
}

You still need a valid API key. Test addresses skip the credit charge, not authentication, so they also confirm that your key and headers are right.

What test addresses don't cover

Three paths can't be produced by a test address, so plan for them separately:

  • processing results. Test addresses answer instantly, so you never see pending. Mock the HTTP layer to return a processing payload, as in the examples below.
  • Typo suggestions. None of the test addresses return a suggestion. Mock that too.
  • Rate limits and credit errors. Test addresses still count toward rate limits. The single endpoint allows 100 requests per minute per API key and batch allows 10, so a test suite that hammers the API in a loop can trigger a 429. Keep live API tests few and run them one after another. To test your 429 branch, mock a response with status 429, a Retry-After: 2 header and the body {"code": "RATE_LIMITED", "message": "Rate limit exceeded.", "data": {"policy": "api.single", "retryAfterSeconds": 2, "limit": 100, "scope": "apiKey", "blocked": false}}, and check that your code waits before it retries.

The pattern that works well: a handful of live tests against the test addresses to prove the integration end to end, plus fast unit tests with a mocked fetch for everything else.

A Node.js test suite

This uses Node's built-in test runner (Node 18+), so there are no dependencies. First, the module under test:

// classify.mjs
export function decide(result) {
  switch (result.category) {
    case "deliverable":
      return "send";
    case "risky":
      return result.status === "disposable" ? "reject" : "review";
    case "undeliverable":
      return "suppress";
    case "pending":
      return "retry-later";
    default:
      return "review"; // anything new
  }
}

export async function verify(email, { fetchImpl = fetch } = {}) {
  const url =
    "https://simplecold.com/api/v1/api-validation/single?email=" +
    encodeURIComponent(email);
  const res = await fetchImpl(url, {
    headers: { Authorization: `Bearer ${process.env.SIMPLECOLD_API_KEY}` },
  });
  const body = await res.json();
  if (!res.ok) throw new Error(body.message ?? body.error);
  return body.payload;
}

Then the tests. The live ones only run when a key is present, so they are skipped on forks and in pull requests from outside contributors:

// classify.test.mjs
import { test } from "node:test";
import assert from "node:assert/strict";
import { decide, verify } from "./classify.mjs";

const live = process.env.SIMPLECOLD_API_KEY ? test : test.skip;

const cases = [
  ["[email protected]", "deliverable", "send"],
  ["[email protected]", "risky", "review"],
  ["[email protected]", "risky", "reject"],
  ["[email protected]", "undeliverable", "suppress"],
];

for (const [email, category, action] of cases) {
  live(`${email} is ${category}`, async () => {
    const result = await verify(email);
    assert.equal(result.category, category);
    assert.equal(decide(result), action);
  });
}

test("processing results are retried later", async () => {
  const fakeFetch = async () => ({
    ok: true,
    json: async () => ({
      code: "SUCCESS",
      payload: {
        email: "[email protected]",
        status: "processing",
        category: "pending",
        statusMessage: "Still checking this mailbox. Ask again in about a minute; you will not be charged again.",
        suggestion: null,
      },
    }),
  });
  const result = await verify("[email protected]", { fetchImpl: fakeFetch });
  assert.equal(decide(result), "retry-later");
});

Run it with node --test. The node test runner runs files in parallel but tests inside a file one after another, so four live calls stay far below the rate limit.

A pytest suite

# test_verify.py
import os
import pytest
import requests

API = "https://simplecold.com/api/v1"
KEY = os.environ.get("SIMPLECOLD_API_KEY")


def verify(email, session=requests):
    res = session.get(
        f"{API}/api-validation/single",
        params={"email": email},
        headers={"Authorization": f"Bearer {KEY}"},
        timeout=30,
    )
    body = res.json()
    if not res.ok:
        raise RuntimeError(body.get("message") or body.get("error"))
    return body["payload"]


live = pytest.mark.skipif(not KEY, reason="SIMPLECOLD_API_KEY not set")


@live
@pytest.mark.parametrize(
    "email,category,status",
    [
        ("[email protected]", "deliverable", "mailbox_found"),
        ("[email protected]", "risky", "no_response"),
        ("[email protected]", "undeliverable", "server_error"),
        ("[email protected]", "risky", "blocked_by_server"),
        ("[email protected]", "risky", "mailbox_unconfirmed"),
    ],
)
def test_live_results(email, category, status):
    result = verify(email)
    assert result["category"] == category
    assert result["status"] == status

Testing the batch and bulk paths

Batch accepts the test addresses in the same request as each other, which makes one call enough to cover every branch:

curl -s https://simplecold.com/api/v1/api-validation/batch \
  -H "Authorization: Bearer $SIMPLECOLD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"emails":["[email protected]","[email protected]","[email protected]","[email protected]"]}'

For bulk, make a small CSV with a header row and upload it. A bulk upload reserves one credit per unique row when the file arrives, and test rows count like any other row, so this three-row fixture uses three credits. Keep bulk fixtures tiny:

printf "email,first_name\[email protected],Ana\[email protected],Ben\[email protected],Cleo\n" > fixtures.csv
curl -s https://simplecold.com/api/v1/api-validation/bulk \
  -H "Authorization: Bearer $SIMPLECOLD_API_KEY" \
  -F "[email protected];type=text/csv"

The response contains the job id. Follow run a bulk job end to end for polling and downloading, and check that your first_name column survives the round trip. Headers come back exactly as you sent them, followed by the result columns such as Result, Reason and Reason code.

Keep test addresses out of production

Test addresses are for development. If one reaches a production sign-up form, it will pass verification and land in your database as a deliverable contact. Block the reserved test domains in production config, or tag records created with them so they never sync to your sending tool.

Once your suite is green, move on to the quickstart if you skipped it, or wire up real traffic with verify emails at sign-up. The API docs keep the current list of test addresses.

Check your list before you send it

Start with 200 free credits. Pay per credit after that.