Skip to content

Integrations

Tested filter configuration for the blocklist. Every directory ships a test suite that runs against the real filter in Docker — not a mock. Querying is free, and a delist request needs no account. If you are designing policy around feeds, start with our pages on domain reputation, IPv6 intelligence, and ASN reputation.

AGPL-3.0 codeFree to query & act onTests against real filters
Start here
You may not need any of this

The DNSBL path needs nothing installed and works with whatever already does RBL lookups.

smtpd_recipient_restrictions =
    permit_mynetworks,
    permit_sasl_authenticated,
    reject_unauth_destination,
    reject_rbl_client dnsbl.vspam.org
Postfix · /etc/postfix/main.cf
Direct block

Prefer canonical phishing domains and exact IPv4 or IPv6 hosts for enforcement. These are the cleanest publication surfaces for SMTP and firewall policy.

Watch & context

Treat IPv6 prefix watch and ASN reputation as triage and policy-tuning signals unless you have stronger direct evidence for a host or domain.

Correction loop

Feed thresholds, delist handling, and false-positive trends are public. Check status, statistics, and delist policy before broad rollout.

Worried about false positives? Anyone can file a delist request without an account. Every request is reviewed by a human within 48 hours and tracked publicly by ID. Approval removes the DNSBL publication and marks the report a false positive in our scoring history.

Delist policy →

Recommended: vspam-agent

Lightweight Go daemon with local caching, fail-open design, and automatic threat reporting. Supports Postfix natively and any MTA via HTTP check API (Exim, OpenSMTPD, Sendmail, etc.).

Download Agent

Firewall & Network Devices

Plain-text blocklists for Palo Alto, FortiGate, pfSense, Juniper SRX, iptables, MikroTik, and more.

Setup Guides
Read this first
Set the Postfix failure mode before you add the dependency

Postfix defaults to 451 4.3.5 Server configuration problem on a 100-second timeout. If you use the agent’s policy service without changing that, the day the agent is restarting, upgrading or wedged, Postfix defers every inbound message — 100 seconds at a time — until someone notices.

A blocklist that stops mail when it cannot be reached is worse than no blocklist.
smtpd_policy_service_default_action = DUNNO
smtpd_policy_service_timeout = 10s
The Ansible role does this for you
What each integration addsOver and above the DNSBL path
rspamd/
1 FILE

Every URL in the message body, a symbol per category, and the suspicious-but-not-listed verdict a DNS return code cannot express.

Install
One config file, or the agent too
rspamd setup →
spamassassin/
SIGNED

Three lookup surfaces and seven scored metas, kept current by a signed update channel.

Install
sa-update --channelSpamAssassin rules →
ansible/
FLEET

The agent across a fleet, with a Postfix failure mode that lets mail through.

Install
One playbook
Ansible role →
mailcow/
2 FILES

Compose override plus an rspamd drop-in, for mailcow deployments.

Install
Two files
mailcow overlay →

Set it up

about 2 minutes
Only the snippets that apply to you
1 · Your platform
2 · How much of it

One line in your resolver. No account, nothing to install, and it checks the connecting IP and the sender.

The DNSBL path is three lines in main.cf. The agent adds policy delegation, a local cache, and reporting.

3 · The file
/etc/postfix/main.cf
smtpd_recipient_restrictions =
  ...
  reject_rbl_client dnsbl.vspam.org
4 · Check it worked
bash
dig +short 19.72.234.185.dnsbl.vspam.org
# 127.0.0.2 means listed (IP listings always answer .2); no answer means not listed

Blocking something you should not be? Delist requests are reviewed by a human within 48 hours, need no account, and are tracked publicly by ID. Check what we hold on a host first with lookup.

More Than One Server

The builder above configures one host. For a fleet there is an Ansible role that installs the agent from the signed package repository, writes its config, starts it, waits until it actually answers, and — if you ask it to — points Postfix at it with a failure mode that lets mail through rather than deferring it.

one command per fleetbash
git clone https://github.com/vspam-org/integrations
cd integrations/ansible
cp inventory.example.ini inventory.ini   # edit
ansible-playbook -i inventory.ini playbook.yml

Idempotent, so it is safe in a nightly run. Debian, Ubuntu, RHEL, Rocky and Alma. Role and variables.

DNSBL return codes

dnsbl.vspam.org

Matching anywhere in 127.0.0.0/8 treats every listing alike, which is the safe default. Category subzones are filtered views of that same list, so a subzone only returns anything for indicators observed in that category — several are defined but sparsely populated today, and an empty answer is not a fault. Phishing is by far the largest category.

Adding a subzone check gains you nothing over the main zone unless you intend to score that category differently.

The codes and subzones below apply to domains. IP listings carry no category: they are published in dnsbl.vspam.org only and always answer 127.0.0.2.

127.0.0.2Phishingphishing.dnsbl.vspam.org
127.0.0.3Malwaremalware.dnsbl.vspam.org
127.0.0.4Botnet C2botnet.dnsbl.vspam.org
127.0.0.5Spamspam.dnsbl.vspam.org
127.0.0.6Tor exittor.dnsbl.vspam.org
127.0.0.7Aggregatedthreats.dnsbl.vspam.org
Check a listing by hand
dig +short 19.72.234.185.dnsbl.vspam.org
# 127.0.0.2 → listed (IP listings always answer .2)
# no answer → not listed
Exact IPv6 host check
curl "api.vspam.org/api/v1/rbl/check?ip=2001:db8::25"
Tests

Docker, plus ansible-playbook for the Ansible suite. Nothing else. They run against real filters because untested rules do not belong in anyone’s mail path.

./rspamd/test/run-tests.sh
./spamassassin/test/run-tests.sh --channel
./ansible/test/run-tests.sh

Security Tools

Fail2Ban/etc/fail2ban/action.d/vspam.conf

Auto-report banned IPs to vspam.org when Fail2Ban triggers an action.

# /etc/fail2ban/action.d/vspam.conf
[Definition]
actionban = curl -s -X POST https://api.vspam.org/api/v1/reports \
  -H "X-API-Key: <YOUR_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"ioc_type":"ip","ioc_value":"<ip>","category":"spam","evidence":"Fail2Ban: <name> jail"}'
Firewall (iptables / nftables)

Pull operator-focused feeds such as exact IPv6 hosts, phishing domains, or IPv6 prefix watchlists and apply them directly to your firewall ruleset.

# Download and apply IPv6 exact-host blocklist
curl -s -H "X-API-Key: <KEY>" https://api.vspam.org/api/v1/feeds/ipv6-exact-host-malicious/csv \
  | tail -n +2 | cut -d',' -f2 | grep ':' \
  | while read ip; do iptables -A INPUT -s "$ip" -j DROP; done

Threat Feeds

Pull operator-focused feeds for phishing domains, exact IPv6 hosts, IPv6 prefix watch, and ASN abuse density in structured formats for OpenCTI, MISP, SIEM, or custom pipelines. CSV, JSON, and plain-text downloads are public. STIX and MISP are Pro, and TAXII is Enterprise.

STIX 2.1
Structured intelinvestigate
GET /api/v1/feeds/stix
Pro tier + auth
MISP
Structured intelinvestigate
GET /api/v1/feeds/misp
Pro tier + auth
Phishing Domains (CSV)
Domain feedblock
GET /api/v1/feeds/domain-high-confidence-phish/csv
public
IPv6 Exact Hosts (JSON)
Exact-host feedblock
GET /api/v1/feeds/ipv6-exact-host-malicious/json
public
IPv6 Prefix Watch (TXT)
IPv6 watch feedwatch
GET /api/v1/feeds/ipv6-prefix-watch/txt
public
ASN Abuse Density (JSON)
ASN reputationcontext
GET /api/v1/feeds/asn-high-abuse-density/json
public
TAXII 2.1
Structured intelinvestigate
GET /taxii2/
Enterprise tier + auth
Operator guidance

Use block feeds for direct enforcement, watch feeds for escalation and guardrails, and context feeds for correlation and prioritization. The methodology and publication thresholds are visible in the feed catalog.

API Quick Start

Common curl examples — replace <KEY> with your API key from the account page.

# Check an IP
curl https://api.vspam.org/api/v1/rbl/check?ip=192.0.2.1

# Check a phishing domain
curl "https://api.vspam.org/api/v1/public/operator-lookup?type=domain&value=login-paypa1.com"

# Check ASN reputation context
curl "https://api.vspam.org/api/v1/public/operator-lookup?type=asn&value=AS13335"

# Search reports
curl https://api.vspam.org/api/v1/public/reports?q=example.com

# Submit a phishing report (URLs normalize to canonical domains at ingest)
curl -X POST https://api.vspam.org/api/v1/reports \
  -H "X-API-Key: <KEY>" \
  -d '{"ioc_type":"url","ioc_value":"https://phish.example.com","category":"phishing"}'

SDK Examples

Query the vspam.org API from your application. Replace <KEY> with your API key.

Pythonrequests
import requests

API = "https://api.vspam.org/api/v1"
KEY = "<KEY>"

# Check a phishing domain
domain_lookup = requests.get(
    f"{API}/public/operator-lookup",
    params={"type": "domain", "value": "login-paypa1.com"},
)
print(domain_lookup.json())

# Check an exact IPv6 host
ipv6_lookup = requests.get(
    f"{API}/rbl/check",
    params={"ip": "2001:db8::42"},
)
print(ipv6_lookup.json())

# Submit a report
requests.post(f"{API}/reports",
    headers={"X-API-Key": KEY},
    json={"ioc_type": "url",
          "ioc_value": "https://phish.example.com",
          "category": "phishing"})
Gonet/http
package main

import (
    "fmt"
    "io"
    "net/http"
)

func main() {
    domainResp, _ := http.Get(
        "https://api.vspam.org/api/v1/public/operator-lookup?type=domain&value=login-paypa1.com")
    defer domainResp.Body.Close()
    domainBody, _ := io.ReadAll(domainResp.Body)
    fmt.Println(string(domainBody))

    ipResp, _ := http.Get(
        "https://api.vspam.org/api/v1/rbl/check?ip=2001:db8::42")
    defer ipResp.Body.Close()
    ipBody, _ := io.ReadAll(ipResp.Body)
    fmt.Println(string(ipBody))
}
Node.jsfetch
const API = "https://api.vspam.org/api/v1";
const KEY = "<KEY>";

// Check a canonical domain
const domainRes = await fetch(
  `${API}/public/operator-lookup?type=domain&value=login-paypa1.com`);
console.log(await domainRes.json());

// Check an exact IPv6 host
const ipv6Res = await fetch(
  `${API}/rbl/check?ip=2001:db8::42`);
console.log(await ipv6Res.json());

// Submit a report
await fetch(`${API}/reports`, {
  method: "POST",
  headers: {
    "X-API-Key": KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    ioc_type: "domain",
    ioc_value: "phish.example.com",
    category: "phishing",
  }),
});
PowerShellInvoke-RestMethod
$api = "https://api.vspam.org/api/v1"

# Check a phishing domain
Invoke-RestMethod "$api/public/operator-lookup?type=domain&value=login-paypa1.com"

# Check an exact IPv4 or IPv6 host
Invoke-RestMethod "$api/rbl/check?ip=192.0.2.1"

# Submit a report
$headers = @{ "X-API-Key" = "<KEY>" }
$body = @{
    ioc_type  = "ip"
    ioc_value = "185.234.72.19"
    category  = "spam"
} | ConvertTo-Json

Invoke-RestMethod "$api/reports" `
    -Method Post -Headers $headers `
    -Body $body -ContentType "application/json"

Say So On Your Site

A public SVG endpoint, no key needed, cached for an hour. Reporters get a second badge carrying their confirmed count — the snippet is on your account.

protected by vspam.org
README.mdmarkdown
[![protected by vspam.org](https://api.vspam.org/api/v1/badge/protected.svg)](https://vspam.org/)

If we get one wrong

Reviewed within 48h

No account, no fee, reviewed by a human. False positives are the failure mode that matters and they are only visible to the person affected — so telling us is the contribution.

Licence

Code
AGPL-3.0
Query & act on data
Free

Filtering your own mail costs nothing, however much of it there is — commercially or not, no registration. Redistributing the data (mirroring zones, repackaging, reselling, embedding it in a product) needs a licence.

Need help? Check the API documentation or FAQ. For SIEM and threat intel platform guides, see SIEM Integrations and Threat Intel Platforms.