John, et al --

...and then Dillon, John said...
% > It may be sacrilege to mention it here, but there is an excellent perl
% > module for handling mail bounces; I've used it to write a handler that
% I'd be interested in more details on this, from the pov of a person who

No problem.

% primarily knows php and only dabbled in perl, as I've never got anything to

Heh.  If you can't get a helloworld working we should probably take
things one step at a time :-)  But don't worry; I can help you a bit and
there are excellent perl lists just like these excellent php lists exist.

% work in Perl. Do I envisage a .pl file on the server, is there a reference
% to this near the mail() php sending function etc... who does it tie
% together.  Can the mail be first sent with mail() or does it have to be sent

Let's back up a moment...  The original request was for a way to go
through a stack of mail bounces to pull out the intended addressee and
the reason for the bounce.  My need was to handle bounces as they came
in, ascertain the same thing, and then go and update my DB.  In either
case, the mail was sent long ago and is completely separate from handling
the incoming (or present) bounce.  It doesn't matter what sort of mail
function you use; it can be sent via morse code over a 110baud modem if
you like :-)

% with a perl mail function?  If the answer is too perl-intensive then reply
% off-group but I think it is of interest to php beginners to know what the
% alternatives are and how they might be dipped in and out of.

OK, so on to the script.  Just as PHP has classes, perl has modules which
implement object code.  Just as PHP has PEAR (I think; I'm still getting
to know it), perl has CPAN, the Comprehensive Perl Archive Network.  One
advantage of perl's maturity is an almost ridiculously vast wealth of
contributed modules; if you want to do it, someone has almost certainly
already written a module for it.  [This is already on the way for PHP
and PEAR; in just a few years I, too, predict that PHP will be hugely
popular.]  The one used here is Mail::DeliveryStatus::BounceParser.

Once we set up the script to use the module with

  ### basic setup       ## {{{
  use strict ;                                          # watch your knuckles!
  use warnings ;                                                # only slightly kinder
  use DBI ;                                             # talking to a database
  use DBD::mysql ;                                      # what kind of database?
  use Mail::DeliveryStatus::BounceParser ;              # parsing magic
  ## }}}

catching the mail is literally as easy as

  ### catch the input   ## {{{
  my $bounce = eval { Mail::DeliveryStatus::BounceParser->new ( \*STDIN ) } ;
  if ( $@ )
    print "Whoa -- one we actually couldn't handle!\n" ;
    exit 255 ;
  }     ## }}}

and then, once we make the DB connection, handling the message is also as
easy as

  ### loop thru the message     ## {{{
  foreach my $report ( $bounce->reports )                       # loop thru reports 
for each addr in the bounce
    ### I'd love to grab the *current* M-ID: here...  maybe someday
    my $orig_mid = $bounce->orig_message_id;            # 
    my $email = $report->get('email') ;                 # bouncing address
    my $std_reason = $report->get('std_reason') ;               # why
    my $reason = $report->get('reason') ;                       # other why
    my $date = $report->get('arrival-date') ;           # bounce date
    my ($sec,$min,$hour,$mday,$mon,$year) = localtime ; $year += 1900 ; $mon++ ;
    $date = $date ? $date : "$year-$mon-$mday ${hour}:${min}:$sec" ;    # be sure we 
have a date
    $ur->execute($email) ;                              # update user record
    $br->execute($email,$std_reason,$reason,$orig_mid,$date) ;  # update bounce log
  }     ## foreach(@reports)    ## }}}

and we're done!  The hardest part was figuring out that I had to loop
through $bounce->reports because it wasn't clear in the man page for the
module *blush*.

Back, for a moment, to the DB connection...  perl lets you set up or
"prepare" multiple connections and queries in advance, and then you just
feed one the data for that iteration and off you go.  That's what $ur and
$br are above, and the connection piece that I glossed over looks like

  ### make DB connection        ## {{{
  my $drh = DBI->install_driver("mysql")                        # talking mysql
    or die("Cannot install mysql driver!\n") ;
  my $eteam = $drh->connect("##DBNAME","##DBACCT","##DBPASS",{AutoCommit => 1}) # hook 
    or die("Cannot connect to database server!\n") ;

  ### prepare query
  my $u = "update eteam.USER set FLAG_CONFIRM = 2 where EMAIL = ?" ;    # user status 
  my $b = "insert into eteam.MAIL_BOUNCE values (?,?,?,?,?)" ;  # bounce mail log query
  my $ur = $eteam->prepare($u) ;                                # prepare query (user)
  my $br = $eteam->prepare($b) ;                                # prepare query 
  ## }}}

where the '?' is a placeholder for the values you'll provide at execution
time.  This, IMHO, is a pretty slick feature; it essentially turns your
query string + resource connection into a function that accepts your
varying input and then executes the call.

So there you have it...  This perl script is only 58 lines long and
handles just about every sort of bounce known to man and then goes and
updates two DB tables with the info it pulls out.  It's called from the
apparent sender's .qmail (like .forward) file, which also dumps a copy of
the message onto a mail spool for us to review if we ever need to.


David T-G                      * There is too much animal courage in 
(play) [EMAIL PROTECTED] * society and not sufficient moral courage.
(work) [EMAIL PROTECTED]  -- Mary Baker Eddy, "Science and Health"      Shpx gur Pbzzhavpngvbaf Qrprapl Npg!

Attachment: pgp00000.pgp
Description: PGP signature

Reply via email to