diff --git a/TODO b/TODO
index dc909e92b07744c972301cb64d6740a018c99415..cf3e57cc8337c77a16e9a098384ef2a51c10f674 100644
--- a/TODO
+++ b/TODO
@@ -1,3 +1,6 @@
+Added Message-ID header to DSN with SRS signed sender.  When seen on incoming
+rfc ignorant failure message, blacklist sender.
+
 Allow verified hostnames for trusted_relay.  E.g. HELO name that
 passes SPF.
 
diff --git a/bms.py b/bms.py
index ae62d4025d3c777570eab3da920ca172565255fe..11d50f7a208acedc43f3a0833d0aacefafbfdc86 100644
--- a/bms.py
+++ b/bms.py
@@ -1,6 +1,11 @@
 #!/usr/bin/env python
 # A simple milter that has grown quite a bit.
 # $Log$
+# Revision 1.55  2006/02/17 05:04:29  customdesigned
+# Use SRS sign domain list.
+# Accept but do not use for training whitelisted senders without SPF pass.
+# Immediate rejection of unsigned bounces.
+#
 # Revision 1.54  2006/02/16 02:16:36  customdesigned
 # User specific SPF receiver policy.
 #
@@ -753,6 +758,8 @@ class bmsMilter(Milter.Milter):
     if hostname == 'GC':
       n = gc.collect()
       self.log("gc:",n,' unreachable objects')
+      self.log("auto-whitelist:",len(auto_whitelist),' entries')
+      self.log("cbv_cache:",len(cbv_cache),' entries')
       self.setreply('550','5.7.1','%d unreachable objects'%n)
       return Milter.REJECT
     return Milter.CONTINUE
@@ -935,9 +942,6 @@ class bmsMilter(Milter.Milter):
 	  res,code,txt = q.best_guess('v=spf1 a/24 mx/24')
 	else:
 	  res,code,txt = q.best_guess()
-        if q.perm_error:	# FIXME: should never happen?
-          res,code,txt = q.perm_error.ext	# extended result
-	  txt = 'EXT: ' + txt
       if self.missing_ptr and ores == 'none' and res != 'pass' \
       		and hres != 'pass':
 	policy = p.getNonePolicy()
@@ -1638,6 +1642,9 @@ class bmsMilter(Milter.Milter):
 	template = file(template_name).read()
       except IOError: template = None
       m = dsn.create_msg(q,self.recipients,msg,template)
+      if srs:
+	msgid = srs.forward(sender,self.receiver)
+	m.add_header('Message-Id','<%s>'%msgid)
       m = m.as_string()
       print >>open('last_dsn','w'),m
       res = dsn.send_dsn(sender,self.receiver,m)
diff --git a/spf.py b/spf.py
index 82cb128a3229920eccc30ff83924bf1d2362895b..428673a020022d6d0f7f04f3cda637c4f7906530 100755
--- a/spf.py
+++ b/spf.py
@@ -47,6 +47,9 @@ For news, bugfixes, etc. visit the home page for this implementation at
 # Terrence is not responding to email.
 #
 # $Log$
+# Revision 1.18  2005/12/29 19:15:35  customdesigned
+# Handle NULL MX
+#
 # Revision 1.17  2005/12/23 21:44:15  customdesigned
 # Always include keyword data in Received-SPF header.
 #
@@ -507,6 +510,8 @@ class query(object):
 		except TempError,x:
 			return ('error', 450, 'SPF Temporary Error: ' + str(x))
 		except PermError,x:
+		    if not self.perm_error:
+		      self.perm_error = x
 		    self.prob = x.msg
 		    if x.mech:
 		      self.mech.append(x.mech)
@@ -577,7 +582,7 @@ class query(object):
 		  arg = self.expand(arg)
 		  if not (0 < arg.find('.') < len(arg) - 1):
 		    raise PermError('Invalid domain found (use FQDN)',
-			  arg)
+			  m+':'+arg)
 		  if m == 'include':
 		    if arg == self.d:
 		      if mech != 'include':