# Email Blacklist Checker (DNSBL) & Deliverability · SiteVerdict (`siteverdict/siteverdict-email-blacklist-checker`) Actor

Check domains and mail-server IPs against DNS blocklists whose terms allow it (plus Spamhaus/Abusix with your own key), with listing reasons, delisting links, SPF/DKIM/DMARC summary and alerts when you get listed or delisted.

- **URL**: https://apify.com/siteverdict/siteverdict-email-blacklist-checker.md
- **Developed by:** [Aman Thakran](https://apify.com/siteverdict) (community)
- **Categories:** Developer tools
- **Security:** Limited permissions
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## SiteVerdict — Email Blacklist & Deliverability Checker

**Find out whether your mail servers are on a blocklist, and why, before your emails start landing in spam.**

Enter domains, IP addresses or email addresses. For each one the Actor:

- finds your mail-server (MX) IPs and the single-IP senders in your SPF record;
- checks them against DNS blocklists whose terms allow it;
- adds Spamhaus, Abusix and SpamRATS when you supply your own query keys;
- reports every listing with its reason and delisting link, plus a plain-English SPF / DKIM / DMARC summary.

Schedule it and you get an alert as soon as you are listed, and again when you are delisted.

### Who it is for

- **Businesses and ecommerce stores** that need their order and marketing emails to arrive.
- **Agencies and MSPs** monitoring many client domains or mail servers.
- **ESP and IT teams** that want an automated daily blocklist check with history.

### Accuracy first: no false "clean"

Most blocklists refuse lookups that come through big public DNS resolvers. Many checkers then silently report "not listed". This Actor first queries each list's RFC 5782 **test entry** (127.0.0.2 / `test`).

- If the list does not answer correctly from the resolver in use, its result is reported as **unknown**, never as clean.
- Refusal codes such as `127.255.255.254` are decoded and never mistaken for listings.

### What you get per target

| Field | Content |
|---|---|
| `verdict` | `listed` / `clean` / `unknown` |
| `listings` | List name, listed IP and its role (MX, SPF sender, input), return-code meaning, the list's TXT reason, delisting URL |
| `ipsChecked` | Each IP found, and where it came from |
| `listsChecked` / `listsUnknown` | Lists that answered reliably, and lists that did not (with the reason) |
| `auth` | MX hosts; SPF record, DNS-lookup count, `all` qualifier and errors; DMARC policy, pct and rua; DKIM keys found on 30+ common selectors with key size; plain-English notes |
| `newlyListed` / `delisted` | Changes since the last run (monitoring) |

Exports:

- `LISTINGS_CSV`: one line per listing.
- `SUMMARY`: lists used with their terms, zone health, and excluded lists with the reason for each.

Run with **Mode = Sample** to see a listed domain, a listed IP and a clean domain, free. The sample uses documentation-only IP ranges.

### Blocklists

| List | Default | Why we may use it |
|---|---|---|
| PSBL | on | "Anybody is free to use PSBL." |
| DroneBL | on | Free for commercial and non-commercial use |
| UCEPROTECT Level 1 | on | Permissive licence; DNS lookups suited to small and medium volumes |
| Spamhaus ZEN + DBL | on **with your DQS key** | Spamhaus' free public mirrors are non-commercial only and refuse cloud resolvers, so we never use them. Your own Data Query Service key works. |
| Abusix Mail Intelligence (IP + domain) | on **with your key** | Abusix offers a free tier with a query key |
| SpamRATS | on **with your key** | Free with a registered API key (not for commercial email-protection providers) |
| UCEPROTECT L2 / L3, Backscatterer | opt-in | Aggressive lists that block whole provider ranges; informational |
| SpamCop, Mailspike | opt-in | Widely used, but we found no published terms for third-party lookups |
| Barracuda, SURBL/URIBL, Spamhaus public mirrors | **excluded** | Registration or a commercial feed is required |
| SORBS, NiX Spam | **excluded** | Shut down |

### Monitoring and alerts

Set **Output = Only changes** and schedule a daily run. You get a row, plus a Slack or webhook alert, only when a target is newly listed or delisted. History is kept in the named state store.

### Optional: AI remediation plan (your own key)

For listed or misconfigured targets, your Anthropic or OpenAI key turns the findings into a step-by-step plan:

- a diagnosis;
- DNS records to fix;
- per-list delisting instructions;
- prevention steps.

The key is stored encrypted and never logged.

### Example input and output

Check one domain's mail servers against blocklists, plus SPF, DMARC and DKIM:

**Input**

```json
{
  "targets": [
    "python.org"
  ]
}
```

**Output** (one dataset item, trimmed; real result from a test run on 14 Oct 2026)

```json
{
  "target": "python.org",
  "type": "domain",
  "verdict": "clean",
  "listedOn": 0,
  "listings": [],
  "ipsChecked": [
    {
      "ip": "188.166.95.178",
      "roles": [
        "mx",
        "spf"
      ],
      "source": "mail.python.org"
    }
  ],
  "listsChecked": [
    "psbl",
    "dronebl",
    "uceprotect-1"
  ],
  "auth": {
    "spf": {
      "status": "pass",
      "lookups": 8,
      "all": "~"
    },
    "dmarc": {
      "policy": "none",
      "valid": true
    },
    "dkim": {
      "selectorsFound": [
        {
          "selector": "google",
          "keyBits": 1024
        },
        {
          "selector": "k2",
          "keyBits": 2048
        }
      ],
      "selectorsChecked": 31
    },
    "notes": [
      "DMARC is p=none (monitoring only)."
    ]
  },
  "summary": "Not listed on 3 blocklist(s) checked for 2 IP(s) and the domain.",
  "chargedEvents": [
    "target-checked"
  ]
}
```

Lists that did not answer reliably appear in `listsUnknown` and are never counted as clean. Targets whose result is `unknown` are not charged (see Pricing).

### Pricing

- **$0.008 per target checked** (domain or IP, including its MX/SPF IPs and the authentication summary)
- **$0.01 per alert delivered**
- **$0.02 per AI plan**

Targets whose result is `unknown`, invalid input and sample mode are never charged. Checking 100 domains costs **$0.80**. Daily monitoring of 10 domains costs about **$2.40 a month**.

### FAQ

**Why is Spamhaus off without a key?** Spamhaus' free public mirrors are licensed for non-commercial use only, and they refuse queries from cloud resolvers. A paid tool using them would break both rules. Add your DQS key and Spamhaus ZEN and DBL are checked.

**My result says "unknown" for a list. Why?** That list refused or ignored queries from the resolver in use. Set your own resolver under "DNS resolvers", or add a keyed list.

**Does it check my outbound IP when I use Gmail or Microsoft 365?** It checks your MX IPs and any single IPs in your SPF record. Large providers' shared IPs are rarely the problem. With a dedicated sending IP, put it in SPF as `ip4:` or enter it as a target.

### Limits

- Up to 1,000 targets per run and 12 IPs per domain by default (configurable up to 50).
- SPF ranges wider than /32 are not expanded.
- Domain-reputation lists (domain blocklists) are only available with a Spamhaus or Abusix key.
- The DKIM summary relies on common selector names; add your own selector if you use a custom one.

### Sources & compliance

- **Blocklist terms (read 2026-10-11):**
  - PSBL https://psbl.org/howto/
  - DroneBL https://dronebl.org/docs/howtouse
  - UCEPROTECT licence https://www.uceprotect.net/en/index.php?m=13\&s=0 and DNS usage https://www.uceprotect.net/en/index.php?m=6\&s=11
  - Spamhaus fair use https://www.spamhaus.org/blocklists/dnsbl-fair-use-policy/
  - SpamRATS https://www.spamrats.com/lists.php
  - Abusix https://www.abusix.com/products/abusix-mail-intelligence/
  - SpamCop https://www.spamcop.net/bl.shtml
  - Mailspike https://mailspike.io/ip_verify
- **Standards:** RFC 5782 (DNS blocklists), RFC 7208 (SPF), RFC 7489 (DMARC), RFC 6376 (DKIM).
- **Data and network:** DNS lookups only, with no web scraping. Blocklist queries are capped per run and are well under the published per-day guidance.
- **Security:** blocklist keys and webhook URLs are secret inputs, redacted from every log line and output. Private, loopback and reserved IPs are never queried.
- **UK GDPR / PECR:** IP addresses can be personal data when they identify an individual's connection. Check IPs and domains you operate or are authorised to monitor. Email addresses are reduced to their domain; only the domain appears in the output.
- Blocklist results are third-party opinions provided "as is". Delisting decisions are made by each list operator.

# Changelog

This Actor's version history is a separate document: https://apify.com/siteverdict/siteverdict-email-blacklist-checker/changelog.md

# Actor input Schema

## `executionMode` (type: `string`):

<b>Live</b> checks your targets. <b>Sample</b> replays recorded DNS answers for two demo domains and one IP (free, no network).

## `targets` (type: `array`):

e.g. example.com, 203.0.113.10, news@example.com. For a domain we check its mail-server (MX) IPs, single-IP SPF senders and (with a key) the domain itself, plus an SPF/DKIM/DMARC summary.

## `lists` (type: `array`):

Leave empty for the defaults: PSBL, DroneBL, UCEPROTECT L1 (free terms verified) plus Spamhaus/Abusix/SpamRATS when you add your own key. Optional: uceprotect-2, uceprotect-3, backscatterer, spamcop, mailspike.

## `spamhausDqsKey` (type: `string`):

Your Spamhaus Data Query Service key. Spamhaus' free public mirrors are for non-commercial use only and refuse cloud resolvers, so Spamhaus is only checked with your own key.

## `abusixKey` (type: `string`):

Your Abusix query key (Abusix offers a free tier).

## `spamratsKey` (type: `string`):

Your free SpamRATS API key (not for commercial email-protection providers).

## `includeMxIps` (type: `boolean`):

Resolve the domain's MX hosts and check their IPs.

## `includeSpfIps` (type: `boolean`):

Check ip4:x.x.x.x entries (/32) in the SPF record: these are usually your outbound sending servers.

## `includeWebIps` (type: `boolean`):

Also check the domain's own A/AAAA IPs (useful when the web server also sends mail).

## `maxIpsPerDomain` (type: `integer`):

Cap on IPs checked per domain.

## `authChecks` (type: `boolean`):

Summarise authentication: SPF validity and DNS-lookup count, DMARC policy, DKIM keys on common selectors.

## `dkimSelectors` (type: `array`):

Your provider's selector names if not common ones (e.g. 'k3', 's1024').

## `fetchListingReasons` (type: `boolean`):

For a listed IP, also read the list's TXT explanation.

## `dnsServers` (type: `array`):

Most blocklists refuse queries from big public resolvers (8.8.8.8, 1.1.1.1). Leave empty to use the platform's resolver; a list that refuses or does not answer its test entry is reported as 'unknown', never 'clean'.

## `outputMode` (type: `string`):

'Only changes' outputs a target only when it was newly listed or delisted since the last run (for daily schedules).

## `stateStoreName` (type: `string`):

Named key-value store with each target's last listings.

## `webhookUrl` (type: `string`):

POSTed when a target is newly listed or delisted. Stored encrypted.

## `slackWebhookUrl` (type: `string`):

Stored encrypted.

## `maxConcurrency` (type: `integer`):

DNS queries are also capped globally.

## `aiEnabled` (type: `boolean`):

Off by default. For listed or misconfigured targets, your LLM (with YOUR key) writes a step-by-step remediation and delisting plan from the findings. One 'ai-fix' event per successful answer; your provider bills tokens separately.

## `aiProvider` (type: `string`):

Which API your key belongs to.

## `aiApiKey` (type: `string`):

Your Anthropic or OpenAI API key. Stored encrypted by Apify, never logged or written to the output.

## `aiModel` (type: `string`):

Leave empty for the default (Anthropic: claude-sonnet-5-5, OpenAI: gpt-5-mini).

## Actor input object example

```json
{
  "executionMode": "live",
  "targets": [
    "python.org"
  ],
  "includeMxIps": true,
  "includeSpfIps": true,
  "includeWebIps": false,
  "maxIpsPerDomain": 12,
  "authChecks": true,
  "fetchListingReasons": true,
  "outputMode": "all",
  "stateStoreName": "siteverdict-email-blacklist-checker",
  "maxConcurrency": 4,
  "aiEnabled": false,
  "aiProvider": "anthropic"
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `files` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "targets": [
        "python.org"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("siteverdict/siteverdict-email-blacklist-checker").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "targets": ["python.org"] }

# Run the Actor and wait for it to finish
run = client.actor("siteverdict/siteverdict-email-blacklist-checker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "targets": [
    "python.org"
  ]
}' |
apify call siteverdict/siteverdict-email-blacklist-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,siteverdict/siteverdict-email-blacklist-checker"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/dCBj9jf6OFksforfL/builds/epkrMUGSZh5fBc0Zd/openapi.json
