Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much

Dealing with Bounced email in multi host server

by oakbox (Chaplain)
on Feb 26, 2005 at 11:25 UTC ( #434764=CUFP: print w/replies, xml ) Need Help??

I have about 12 web sites hosted on my server. 4 of them are pretty hefty web applications with multple users. There are a few community sites with mailing lists. YOU know, how it is. Well, because many of these applications have the capability of sending emails, bounce messages have become a real issue.

Most mail servers don't send a bounced message back to whoever is in the 'reply-to' field (for good reason!). All of those messages get bounced back to the server itself. But it is useless to sift through the 6000 or so double-bounces and spam bounces that come back to the server for those 2 or 3 'real' bounce messages that happen per week. I was just dropping them to /dev/null and explaining to my frustrated customers that there was nothing I could do about it.

I stumbled across this post Detecting bounced mails and thought to myself, "Hey, I already have some experience with POP3 handling (Oakmailer) and that Mail::DeliveryStatus::BounceParser module looks like just the thing I need to make my customers happy campers."

So, without further ado, this is what I came up with:

  1. Dump those bounces into a mailbox.
  2. Use Mail::POP3Client to communicate with that mailbox.
  3. Use Mail::DeliveryStatus::BounceParser to look at each of those messages and find the 'real' bounces
  4. come up with a series of subroutines relating to each of my hosted web sites to see if I can find out where that message originally came from
  5. Alert the sender about the bounce
  6. Anything that doesn't fit into one of those tests are forwarded on to me for that personal touch
  7. All of this is wrapped up into a cron job that runs on the hour
I went through each of my sites and created a bunch of messages that I knew would bounce ( and sent them to a wide variety of domains. This gave me a corpus to run the script against, any messages that weren't detected meant I needed to do some rewriting.

In the end, I spent about an hour and a half writing a script that saves me about 10 times that amount of time per month in handling complaints and trying to track down, "Why didn't my candidate get that email?" questions.

use Mail::POP3Client; use Mail::DeliveryStatus::BounceParser; # the following module is general housekeeping stuff use Oakbox::Main; my $Main = Oakbox::Main->new("adminemail"=>"richard\", "logfile" => "Site_Log.txt", "scratch_dir"=> "/tmp/bouncing/"); # connect to the mailbox my $pop = new Mail::POP3Client( USER => "doublebounce", PASSWORD => "password", HOST=> "", DEBUG => 0 , AUTH_MODE => 'PASS' ); my $count = $pop->Count; if ($count == -1) { die("Unable to read Mail box! Something went horr +ibly wrong here.");} &listletters; exit; #### sub listletters{ my $nummessages=$pop->Count(); foreach my $i (1 ... $nummessages) { # read this message my $mailpiece = $pop->HeadAndBody($i); # Read the message, if it can't be parsed, delete it my $bounce = eval { Mail::DeliveryStatus::BounceParser->new( $mailpi +ece ) }; if ($@) { $pop->Delete( $i ); next; } # couldn't parse. # If it's not a bounce, delete it if(! $bounce->is_bounce()){ $pop->Delete( $i ); next; } # After a bunch of testing, this is the consistent # test for a 'real' bounce if($bounce->orig_message_id() =~ /qmail\{ my @reports = $bounce->reports(); foreach my $report (@reports){ my $email_address = $report->get('email'); my $reason = $report->get('std_reason'); my $orig = $bounce->orig_text(); if($email_address eq ""){ next; } ### This is a series of tests related to different # sites that I'm hosting. If I find the original # message, I email the correct person and return # true, so I know I can delete it. my $ret_code = &check_otm($email_address,$reason,$orig); if($ret_code eq "1"){ $pop->Delete( $i ); next; } # several other tests # It's a bounce, I don't know what to do, # let Richard figure it out my $rawmessage = $report->get('raw'); &default_handler($email_address,$reason,$orig,$rawmessage); $pop->Delete( $i ); } # This message isn't from my server, drop # it }else{ $pop->Delete( $i ); } } # You have to State and Close the POP3 connection # for the messages to actually BE deleted. $pop->State(); $pop->Close(); }
This script processes roughly 1000 messages in 30 seconds on a 1.8 Ghz machine. I was thinking it might be useful to others in a similar situation.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: CUFP [id://434764]
Approved by Corion
Front-paged by grinder
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (3)
As of 2020-03-28 19:00 GMT
Find Nodes?
    Voting Booth?
    To "Disagree to disagree" means to:

    Results (167 votes). Check out past polls.