How to Programmatically Report Spam to Multiple DNSBL/RBL Services for Improved Email Filtering


2 views

As developers managing email infrastructure, we've all encountered the frustration of persistent spam sources that evade single-point reporting systems. Traditional manual reporting to services like SpamCop often proves ineffective for several technical reasons:


// Example spam message headers showing persistent offender
Received: from malicious.host (192.168.1.100)
    by mailserver.example.com (Postfix)
    with ESMTP id ABC1234
X-Spam-Score: 9.8

The core issue stems from how different DNS-based Blackhole Lists (DNSBLs) operate:

  • Most require SMTP-level reporting protocols (like ARF)
  • Many maintain proprietary submission APIs
  • Thresholds for listing vary significantly (Spamhaus requires 10+ reports)

For Python developers, here's a script template to report to multiple RBLs:


import smtplib
import dns.resolver
from email.mime.text import MIMEText

def report_to_rbls(spam_ip, spam_content):
    # Spamhaus submission
    spamhaus_msg = MIMEText(spam_content)
    spamhaus_msg['Subject'] = 'Spam Report'
    spamhaus_msg['From'] = 'abuse@yourdomain.com'
    spamhaus_msg['To'] = 'spam@spamhaus.org'
    
    # URIBL submission (for URL-based spam)
    uribl_msg = MIMEText(f"Spam IP: {spam_ip}\n\n{spam_content}")
    uribl_msg['Subject'] = 'Spam URL Report'
    uribl_msg['From'] = 'abuse@yourdomain.com'
    uribl_msg['To'] = 'submit@uribl.com'
    
    # Execute submissions
    with smtplib.SMTP('your.smtp.server') as server:
        server.send_message(spamhaus_msg)
        server.send_message(uribl_msg)
Service Submission Method API Endpoint
Spamhaus Email/HTTP https://www.spamhaus.org/report/
Barracuda HTTP POST https://www.barracudacentral.org/report
SURBL Email spam@surbl.org

When individual IP reporting fails, consider programmatic /24 blocking:


# iptables example for persistent spam networks
import subprocess

def block_spam_subnet(base_ip):
    subnet = f"{base_ip}/24"
    subprocess.run([
        'iptables',
        '-A', 'INPUT',
        '-s', subnet,
        '-j', 'DROP'
    ])
    # Persist rules
    subprocess.run(['iptables-save', '>', '/etc/iptables.rules'])

Verify if your reports resulted in listings:


import dns.resolver

def check_rbl_listing(ip, rbl_domain='zen.spamhaus.org'):
    reversed_ip = '.'.join(reversed(ip.split('.')))
    query = f"{reversed_ip}.{rbl_domain}"
    try:
        answers = dns.resolver.resolve(query, 'A')
        return [str(r) for r in answers]
    except dns.resolver.NXDOMAIN:
        return False

As developers dealing with email systems, we often encounter spam that slips through filters. While services like SpamCop provide reporting mechanisms, they're just one piece of the puzzle. Many blacklists don't directly accept user submissions, making comprehensive reporting challenging.

DNS-based Blackhole Lists (DNSBLs) or Realtime Blackhole Lists (RBLs) operate differently. Some major ones include:

  • Spamhaus ZEN (combined SBL+XBL+PBL)
  • Barracuda Reputation Block List
  • URIBL (for URI-based filtering)
  • SORBS (historical spam data)

Here's a Python script template for batch reporting to multiple services:

import requests
import dns.resolver

class SpamReporter:
    def __init__(self):
        self.services = {
            'SpamCop': 'https://www.spamcop.net/sc?id=',
            'AbuseIPDB': 'https://www.abuseipdb.com/report/json',
            # Add other API endpoints
        }
    
    def report_ip(self, ip_address, evidence):
        # Example for AbuseIPDB
        params = {
            'key': 'YOUR_API_KEY',
            'ip': ip_address,
            'categories': '3,15',  # 3=Spam, 15=Brute Force
            'comment': evidence[:255]
        }
        response = requests.post(
            self.services['AbuseIPDB'],
            data=params
        )
        return response.json()
    
    def check_dnsbl(self, ip_address):
        dnsbls = [
            'zen.spamhaus.org',
            'bl.spamcop.net',
            'dnsbl.sorbs.net'
        ]
        results = {}
        reversed_ip = '.'.join(reversed(ip_address.split('.')))
        
        for dnsbl in dnsbls:
            try:
                query = f"{reversed_ip}.{dnsbl}"
                answers = dns.resolver.resolve(query, 'A')
                results[dnsbl] = [str(r) for r in answers]
            except dns.resolver.NXDOMAIN:
                results[dnsbl] = 'Not listed'
            except Exception as e:
                results[dnsbl] = f"Error: {str(e)}"
        
        return results

For Postfix users, you can implement automatic reporting via policy servers. Create a simple microservice that:

  1. Receives spam messages via HTTP
  2. Extracts headers and content
  3. Distributes reports to multiple blacklists
# Sample Postfix master.cf configuration
policy-spamreport unix - n n - - spawn
    user=nobody argv=/usr/local/bin/spamreport-service.py

When direct API reporting isn't available:

  • Submit to CERT teams (for ISP-level action)
  • Report to hosting providers' abuse desks
  • Use ARIN/RIPE/APNIC WHOIS abuse contacts

Track your reports with this simple Bash script:

#!/bin/bash
# Check if IP is listed in common DNSBLs
IP=$1
echo "Checking $IP against DNSBLs:"

for bl in zen.spamhaus.org bl.spamcop.net dnsbl.sorbs.net; do
    reversed=$(echo $IP | awk -F. '{print $4"."$3"."$2"."$1}')
    if host -t A ${reversed}.${bl} >/dev/null 2>&1; then
        echo "[LISTED] $bl"
    else
        echo "[CLEAN]  $bl"
    fi
done

Remember that effective spam fighting requires persistence. Combining technical solutions with proper reporting creates stronger defenses for the entire email ecosystem.