#
# Return a doubly-bounced e-mail to postmaster. Specific to sendmail,
# updated to work on sendmail 8.12.6.
#
# Based on the original doublebounce.pl code by jr@terra.net, 12/4/97.
# Updated by bicknell@ufp.org, 12/4/2002 to understand new sendmail DSN
# bounces. Code cleanup also performed, mainly making things more
# robust.
#
# Original intro included below, lines with ##
## attempt to return a doubly-bounced email to a postmaster
## jr@terra.net, 12/4/97
##
## invoke by creating an mail alias such as:
## doublebounce: "|/usr/local/sbin/doublebounce"
## then adding this line to your sendmail.cf:
## O DoubleBounceAddress=doublebounce
##
## optionally, add a "-d" flag in the aliases file, to send a
## debug trace to your own postmaster showing what is going on
##
## this allows the "postmaster" address to still go to a human being,
## while bounce messages can go to this script, which will bounce them
## back to the postmaster at the sending site.
##
## the algorithm is to scan the double-bounce error report generated
## by sendmail on stdin, for the original message (it starts after the
## second "Orignal message follows" marker), look for From, Sender, and
## Received headers from the point closest to the sender back to the point
## closest to us, and try to deliver a double-bounce report back to a
## postmaster at one of these sites in the hope that they can
## return the message to the original sender, or do something about
## the fact that that sender's return address is not valid.
use Socket;
use strict;
# parseaddr()
# parse hostname from From: header
#
sub parseaddr {
my($hdr) = @_;
my($addr);
if ($hdr =~ /<.*>/) {
$addr =~ s/.*\@//;
return $addr;
}
if ($addr =~ /\s*\(/) {
$addr =~ s/.*\@//;
return $addr;
}
$addr =~ s/.*\@//;
return $addr;
}
# sendbounce()
# send bounce to postmaster
#
# this re-invokes sendmail in immediate and quiet mode to try
# to deliver to a postmaster. sendmail's exit status tells us
# whether the delivery attempt really was successful.
#
sub send_bounce {
my($st);
my($result);
if ($opt_d) {
}
sender's address was also invalid. Since the message originated
open(MSG, "<$tmpfile");
close(MSG);
if ($result) {
}
return $result;
}
sub main {
# Get our command line options
getopts('d');
# Set up syslog
setlogsock('unix');
if ($opt_d) {
}
# The bounced e-mail may be large, so we'd better not try to buffer
# it in memory, get a temporary file.
if (!open(MSG, ">$tmpfile")) {
exit(75); # 75 is a temporary failure, sendmail should retry
}
close(MSG);
if (!open(MSG, "<$tmpfile")) {
exit(74); # 74 is an IO error
}
# Ok, now we can get down to business, find the original message
$skip_lines = 0;
$in_header = 0;
$headers_found = 0;
while (<MSG>) {
if ($skip_lines > 0) {
$skip_lines--;
next;
}
chomp;
# Starting message depends on your version of sendmail
# Found the original message
$skip_lines++;
$in_header = 1;
$headers_found++;
next;
}
if (/^$/) {
if ($headers_found >= 2) {
# We only process two deep, even if there are more
last;
}
if ($in_header) {
# We've found the end of a header, scan for the next one
$in_header = 0;
}
next;
}
if ($in_header) {
if (! /^[ \t]/) {
# New Header
if (/^(received): (.*)/i ||
/^(sender): (.*)/i ||
/^(from): (.*)/i ) {
}
next;
} else {
# continuation header
# we should really process these, but we don't yet
next;
}
} else {
# Nothing to do if we're not in a header
next;
}
}
close(MSG);
# Start with the original (inner) sender
if ($opt_d) {
}
last if $sent;
}
if ($opt_d) {
}
if ($opt_d) {
}
last if $sent;
}
if (!$sent) {
}
}
unlink($tmpfile);
}
main();
exit(0);