How To Use DNS Blocklists to Detect Spam

One of the solutions to spam is a -frequent updated- database with IP addresses that appear to misbehave. This database should, preferably, be random accessible at high speed. DNS offers a solution for that.

Fortunately internet has found answers for the immens growing spam problem. A solution is a -frequent updated- database with IP addresses that appear to misbehave. This database should, preferably, be random accessible at high speed. DNS offers a solution for that.

DNS entries can be updated quickly. Also, mostly there is no need to download a copy of the (potentially large) database frequently. If a mail server can detect, in a fraction of a second, that the sending IP is currently blacklisted, for example because it was infected by a virus and used as open relay, it can effictively block reception.

A well-known DNSBL provider is . For a (complete) list of DNSBL providers, look here

Both SMTP servers and mail clients (or mailbox cleaners) can use this method. The path a mail message went is always stored, so you can always retrieve the originating IP. This is an essential part of the SMTP protocol.

Using the POP3 protocol, you can watch a mail box, top (top means: fetch only the message header) headers of messages, and see if they are blacklisted by looking at the "Received: from somehost (" lines.

Since these spam databases can be updated frequently, they can effectively detect a large amount (>50% ?) of spam.

How does it work

Basically, what you need to do is verify against a DNSBL (DNS BlockList) source, like This is done in the following way:

Suppose you want to check if IP adress is a spammer, you just perform a DNS query to, with the (reversed) ip address inserted, like
query dns:
if you get back a A record, this is a spammer. if you get back nothing, this ip is not on the spam list.

Test it
You can easily verify this using the 'ping' command.
if you would do:
ping, then there are two options:
* you get 'unknown host' message. This is ok, the IP is not blacklisted.
* You get '127.0.0.x', where x>1, like X represents a status code. Generally, 2 is used for (semi)permanent netblocks, and 4 is used for 'open proxies' (like: machines infected by a virus).

i use this unit succesfully in a mail client. Lubos has integrated this unit successfully in a SMTP/POP3 server suite.

you can use this unit with or without synapse tcp/ip library by setting the {$DEFINE SYNAPSE} directive.


unit spamchck;


//Query's the database of spammers

uses Classes, SysUtils, {$IFDEF SYNAPSE}SynaUtil, SynSock{$ELSE}WinSock{$ENDIF};

  TSpamCheck = class (TObject)
    FDNSBL:String; //DNS BlockList
    constructor Create;
    function IsSpammer (IP:String):Integer; overload;
    function IsSpammer (MailHeader:TStrings):Integer; overload;


{ TSpamCheck }

constructor TSpamCheck.Create;
  FDNSBL := '';
  // alternatively use (spam) or
  // (open relays, proxys)
  // or an alternative source DNSBL source.
  // the sbl-xbl is the combined list.

function TSpamCheck.IsSpammer(IP: String): Integer;
var RevIP:String;
  //Query the database
  //First, reverse the IP
  Result := -1;
  if IsIP (IP) then
      //Reverse the IP
      RevIP := '';
      for i:=0 to 2 do
          RevIP := '.'+Copy (IP, 1, pos ('.', IP)-1) + RevIP;
          IP := Copy (IP, pos('.', IP)+1, maxint);
      RevIP := IP + RevIP;

      //Now, query the database:
      RevIP := RevIP + '.' + FDNSBL;
      p := GetHostByName (PChar(RevIP));
      if Assigned (p) then
        begin //Results come back as 127.0.0.x where x > 1
              // = spam
              // = open relay etc.
          Result := byte(p^.h_addr^.S_un_b.s_b4);
      else //no dns entry found, mark it as safe:
        Result := 0;


function TSpamCheck.IsSpammer(MailHeader: TStrings): Integer;
var v,ip:String;
  //Parse a email header
  //Look for 'Received' header
  //extract IP address, assuming form 'Received: from (a.b.c.d) by (w.x.y.z)
  //Validate this IP address at spamhaus.
  i := 0;
  Result := -1;
  while i<MailHeader.Count do
      if pos ('received: ', lowercase (MailHeader[i])) = 1 then
          v := MailHeader[i];
          //search for additional headers:
          while ((i+1)<MailHeader.Count) and
                (MailHeader[i+1]<>'') and
                (MailHeader[i+1][1]=' ') do
              inc (i);
              v := v+MailHeader[i];
          //v now contains one line, find from ip address:
          v := lowercase (v);
          //searching for:
          //Received: from (
          v := copy (v, pos ('from', v)+4, maxint);
          v := copy (v, pos ('(', v)+1, maxint);
          v := copy (v, 1, pos (')', v)-1);

          if pos ('[', v)>0 then
            //valid format is also:
            //Received: from ( [])
              v := copy (v, pos ('[', v)+1, maxint);
              v := copy (v, 1, pos (']', v)-1);

          Result := IsSpammer (v);

          //a single received line is sufficient
          if Result > 0 then
      inc (i);



Share this article!

Follow us!

Find more helpful articles: