Tech Corner

Procmail - MIME Bounce Recipe for SpamBouncer

[Last Updated: Thursday, 04-Jun-2009 13:10:33 EDT]

The following procmail recipe is a modified bounce recipe for the SpamBouncer Procmail script. This recipe almost identically reproduces a MIME compliant bounce message that Sendmail would produce on a Linux platform.

Instructions

This recipe should be copied into its own text file with a .rc extension and saved in your source directory for the SpamBouncer script. It should be called from the main sb.rc file included with SpamBouncer with this syntax

INCLUDERC=<filename>.rc

The included bounce routine in the sb.rc file should be disabled by modifying the specific recipe like this...

:0
* !
* BOUNCETHIS ?? yes
* !ADMINTAG ?? yes
* !BULKTAG ?? yes
* !VIRUSTAG ?? yes

Set the CHECKSUM variable to the path to a local md5 checksum program.
If you have multiple aliases for your mailbox, for example your own personal domain name with multiple addresses pointing to one mailbox, create a file called .myaliases and list each alias on a separate line with no spaces or blank lines.
Also make sure that the variable MYEMAIL_ is set to your primary email alias. This will be used as the failed address by default if the Received headers are fooled into not including the destination address.


DISCLAIMER
 
No Warranty of any kind is expressed or implied with respect to the information contained in this document!
The information found here is compiled for the convenience of anyone looking for general guidelines and best practices for configuration based on my own professional experience, as well as industry standards.
Use this information at your own risk!
 
Scott S. 2009


# Based on the bounce code from spambouncer by Catherine A. Hampton, http://www.spambouncer.org/
#
# Modified by paul(at)it.ca for MIME support
# Modified by scott(at)thewaystation.com to mimic Sendmail on Linux
#

CHECKSUM=/usr/bin/md5sum
DQ='"'
RCPTFAIL=none

# BOUNCE ROUTINE
:0
* BOUNCETHIS ?? yes || BLOCKTHIS ?? yes
* !ADMINTAG ?? yes
* !BULKTAG ?? yes
* !VIRUSTAG ?? yes
{
  :0
  { BOUNCEPID=`echo $$` }
	
  :0 c:
  bouncetemp.${BOUNCEPID}

  :0
  { SPAMFROM=`${FORMAIL} -rt -xTo:` }

  :0
  * ^Errors-to:[ 	]\/.*
  { SPAMERROR=$MATCH }

  :0
  { SPAMDATE=`date` }

  # Create reply headers using the Return-Path header
  # Compliant with RFC822
  :0
  { BOUNCEFLAGS=-r }

  # If the Return-Path is bogus, then the email is almost 100% certain to be
  # Spam. Probably shouldn't generate a bounce in this case. In order to 
  # bounce you'll have to use the From address.
  # This method is not compliant with RFC822
  :0
  * !^Return-Path:.*[0-9a-zA-Z]@[0-9a-zA-Z]
  { BOUNCEFLAGS=-rt }

  :0
  {
    # For FreeBSD:
    # MIMEBREAK="`echo \"${SPAMDATE} $$\" | ${CHECKSUM} | sed -e 's/  -//'`.`date '+%s'`/${HOST}.${DOMAIN}"

    # For Solaris (could be better):
    #MIMEBREAK="${BOUNCEPID}.`date '+%s'`/${HOST}.${DOMAIN}"

    # For Linux:
    # SendMail appears to use the following for the MIME separator... 
    # "`<SendMail MessageQueue ID>`.`date '+%s'`/${HOST}.${DOMAIN}"
    # Not sure how SendMail creates Message Queue IDs so we'll just checksum
    # the message, clean it up, and prepend it to the date and hostname.
    MIMEBREAK="`cat bouncetemp.${BOUNCEPID} | ${CHECKSUM} | sed -e 's/  -//'`.`date '+%s'`/${HOST}.${DOMAIN}"
  }

  # Match Received: header against myaliases file
  # If matched set address to RCPTFAIL variable
  :0
  * ? ${TEST} -f ${MYALIASES} && \
    (${FORMAIL} -uReceived: | ${FORMAIL} -xReceived: \
    | ${GREP} -i -f ${MYALIASES})
  { RCPTFAIL=`${FORMAIL} -uReceived: | ${FORMAIL} -cxReceived: \
              | sed -e 's/^.*for <//' -e 's/>;.*$//' \
              | tr A-Z a-z` }

  :0
  * RCPTFAIL ?? none
  { RCPTFAIL=$MYEMAIL_ }

  # Isolate the sending MTA IP or hostname
  # Strip out the sending MTA IP Address
  :0
  { RCPTMTAIP=`${FORMAIL} -uReceived: | ${FORMAIL} -cxReceived: \
               | sed -e 's/^.*\[//' -e 's/\].*$//'` }

  # Set the reverse lookup variable
  :0
  { RCPTMTADOMAIN=`${NSLOOKUP} ${RCPTMTAIP}` }

  # If no reverse lookup just use the IP address
  :0
  * RCPTMTADOMAIN ?? (not found|NXDOMAIN)
  { RCPTMTA=`echo Unresolved [${RCPTMTAIP}]` }

  # Or else chop just the hostname out of the results
  :0 E
  { RCPTMTA=`echo ${RCPTMTADOMAIN} \
    | sed -e 's/^.*pointer //' -e 's/.$//'` }

  :0 c: bouncetemp.${BOUNCEPID}.lock
  | ( ${FORMAIL} ${BOUNCEFLAGS} \
	-I"From: MAILER-DAEMON@${HOST}.${DOMAIN} (Mail Delivery Subsystem)" \
	-I"Subject: Returned mail: see transcript for details" \
	-I"Auto-Submitted: auto-generated (failure)" \
	-I"MIME-Version: 1.0" \
	-I"Content-Type: multipart/report; report-type=delivery-status; boundary=${DQ}${MIMEBREAK}${DQ}" \
	-A"X-Loop: MAILER-DAEMON@${HOST}.${DOMAIN}" \
     printf "\nThis is a MIME-encapsulated message\n";\
     printf "\n--%s\n\n" "${MIMEBREAK}";\
     printf "The original message was received at %s\n" "${SPAMDATE}";\
     printf "from %s\n\n" "${SPAMFROM}";\
     printf "\n   ----- The following addresses had permanent fatal errors -----";\
     printf "\n%s\n" "<${RCPTFAIL}>";\
     printf "    (reason: 550 %s... User unknown)\n\n" "<${RCPTFAIL}>";\
     printf "   ----- Transcript of session follows -----\n";\
     printf "... while talking to ${HOST}.${DOMAIN}.:\n";\
     printf ">>> RCPT To:%s\n" "<${RCPTFAIL}>";\
     printf "<<< 550 %s... User unknown\n" "<${RCPTFAIL}>";\
     printf "550 5.1.1 %s... User unknown\n" "<${RCPTFAIL}>";\
     printf "\n--%s\nContent-Type: message/delivery-status\n\n" "${MIMEBREAK}";\
     printf "Reporting-MTA: dns; %s\n" "${HOST}.${DOMAIN}";\
     printf "Received-From-MTA: DNS; %s\n" "${RCPTMTA}";\
     printf "Arrival-Date: %s\n\n" "${SPAMDATE}";\
     printf "Final-Recipient: RFC822; %s\n" "${RCPTFAIL}";\
     printf "Action: failed\nStatus: 5.1.1\n";\
     printf "Remote-MTA: DNS; localhost\n";\
     printf "Diagnostic-Code: SMTP; 550 %s... User unknown\n" "<${RCPTFAIL}>";\
     printf "Last-Attempt-Date: %s\n" "${SPAMDATE}";\
     printf "\n--%s\nContent-Type: message/rfc822\n\n" "${MIMEBREAK}";\
     cat bouncetemp.${BOUNCEPID};\
     printf "\n--%s--\n\n" "${MIMEBREAK}";\
     ${RM} -f bouncetemp.${BOUNCEPID} \
   ) | ${SENDMAIL} -od -t
}

DISCLAIMER
 
No Warranty of any kind is expressed or implied with respect to the information contained in this document!
The information found here is compiled for the convenience of anyone looking for general guidelines and best practices for configuration based on my own professional experience, as well as industry standards.
Use this information at your own risk!
 
Scott S. 2009

Last Revised: Thursday, 04-Jun-2009 13:10:33 EDT


Privacy Statement   SSL Security by 
www.cacert.org