.\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .if !\nF .nr F 0 .if \nF>0 \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} .\} .\" ======================================================================== .\" .IX Title "Mail::DeliveryStatus::BounceParser 3pm" .TH Mail::DeliveryStatus::BounceParser 3pm "2018-09-28" "perl v5.26.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Mail::DeliveryStatus::BounceParser \- Perl extension to analyze bounce messages .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 1 \& use Mail::DeliveryStatus::BounceParser; \& \& # $message is \e*io or $fh or "entire\enmessage" or \e@lines \& my $bounce = eval { Mail::DeliveryStatus::BounceParser\->new($message); }; \& \& if ($@) { \& # couldn\*(Aqt parse. \& } \& \& my @addresses = $bounce\->addresses; # email address strings \& my @reports = $bounce\->reports; # Mail::Header objects \& my $orig_message_id = $bounce\->orig_message_id; # \& my $orig_message = $bounce\->orig_message; # Mail::Internet object .Ve .SH "ABSTRACT" .IX Header "ABSTRACT" Mail::DeliveryStatus::BounceParser analyzes \s-1RFC822\s0 bounce messages and returns a structured description of the addresses that bounced and the reason they bounced; it also returns information about the original returned message including the Message-ID. It works best with \s-1RFC1892\s0 delivery reports, but will gamely attempt to understand any bounce message no matter what \s-1MTA\s0 generated it. .SH "DESCRIPTION" .IX Header "DESCRIPTION" Meng Wong wrote this for the Listbox v2 project; good mailing list managers handle bounce messages so listowners don't have to. The best mailing list managers figure out exactly what is going on with each subscriber so the appropriate action can be taken. .SS "parse" .IX Subsection "parse" .Vb 1 \& my $bounce = Mail::DeliveryStatus::BounceParser\->parse($message, \e%arg); .Ve .PP \&\s-1OPTIONS.\s0 If you pass BounceParser\->new(..., {log=>sub { ... }}) That will be used as a logging callback. If \f(CW$message\fR is undefined, will parse \s-1STDIN.\s0 .PP NON-BOUNCES. If the message is recognizably a vacation autoresponse, or is a report of a transient nonfatal error, or a spam or virus autoresponse, you'll still get back a \f(CW$bounce\fR, but its \f(CW\*(C`$bounce\->is_bounce()\*(C'\fR will return false. .PP It is possible that some bounces are not really bounces; such as anything that appears to have a 2XX status code. To include such non-bounces in the reports, pass the option {report_non_bounces=>1}. .PP For historical reasons, \f(CW\*(C`new\*(C'\fR is an alias for the \f(CW\*(C`parse\*(C'\fR method. .SS "log" .IX Subsection "log" .Vb 1 \& $bounce\->log($messages); .Ve .PP If a logging callback has been given, the message will be passed to it. .SS "is_bounce" .IX Subsection "is_bounce" .Vb 1 \& if ($bounce\->is_bounce) { ... } .Ve .PP This method returns true if the bounce parser thought the message was a bounce, and false otherwise. .SS "reports" .IX Subsection "reports" Each \f(CW$report\fR returned by \f(CW$bounce\fR\->\fIreports()\fR is basically a Mail::Header object with a few modifications. It includes the email address bouncing, and the reason for the bounce. .PP Consider an \s-1RFC1892\s0 error report of the form .PP .Vb 2 \& Reporting\-MTA: dns; hydrant.pobox.com \& Arrival\-Date: Fri, 4 Oct 2002 16:49:32 \-0400 (EDT) \& \& Final\-Recipient: rfc822; bogus3@dumbo.pobox.com \& Action: failed \& Status: 5.0.0 \& Diagnostic\-Code: X\-Postfix; host dumbo.pobox.com[208.210.125.24] said: 550 \& : Nonexistent Mailbox .Ve .PP Each \*(L"header\*(R" above is available through the usual \fIget()\fR mechanism. .PP .Vb 6 \& print $report\->get(\*(Aqreporting_mta\*(Aq); # \*(Aqsome.host.com\*(Aq \& print $report\->get(\*(Aqarrival\-date\*(Aq); # \*(AqFri, 4 Oct 2002 16:49:32 \-0400 (EDT)\*(Aq \& print $report\->get(\*(Aqfinal\-recipient\*(Aq); # \*(Aqrfc822; bogus3@dumbo.pobox.com\*(Aq \& print $report\->get(\*(Aqaction\*(Aq); # "failed" \& print $report\->get(\*(Aqstatus\*(Aq); # "5.0.0" \& print $report\->get(\*(Aqdiagnostic\-code\*(Aq); # X\-Postfix; ... \& \& # BounceParser also inserts a few interpretations of its own: \& print $report\->get(\*(Aqemail\*(Aq); # \*(Aqbogus3@dumbo.pobox.com\*(Aq \& print $report\->get(\*(Aqstd_reason\*(Aq); # \*(Aquser_unknown\*(Aq \& print $report\->get(\*(Aqreason\*(Aq); # host [199.248.185.2] said: 550 5.1.1 unknown or illegal user: somebody@uss.com \& print $report\->get(\*(Aqhost\*(Aq); # dumbo.pobox.com \& print $report\->get(\*(Aqsmtp_code\*(Aq); # 550 \& \& print $report\->get(\*(Aqraw\*(Aq) || # the original unstructured text \& $report\->as_string; # the original structured text .Ve .PP Probably the two most useful fields are \*(L"email\*(R" and \*(L"std_reason\*(R", the standardized reason. At this time BounceParser returns the following standardized reasons: .PP .Vb 8 \& user_unknown \& over_quota \& user_disabled \& domain_error \& spam \& message_too_large \& unknown \& no_problemo .Ve .PP The \*(L"spam\*(R" standard reason indicates that the message bounced because the recipient considered it spam. .PP (no_problemo will only appear if you set {report_non_bounces=>1}) .PP If the bounce message is not structured according to \s-1RFC1892,\s0 BounceParser will still try to return as much information as it can; in particular, you can count on \*(L"email\*(R" and \*(L"std_reason\*(R" to be present. .SS "addresses" .IX Subsection "addresses" Returns a list of the addresses which appear to be bouncing. Each member of the list is an email address string of the form 'foo@bar.com'. .SS "orig_message_id" .IX Subsection "orig_message_id" If possible, returns the message-id of the original message as a string. .SS "orig_message" .IX Subsection "orig_message" If the original message was included in the bounce, it'll be available here as a message/rfc822 \s-1MIME\s0 entity. .PP .Vb 1 \& my $orig_message = $bounce\->orig_message; .Ve .SS "orig_header" .IX Subsection "orig_header" If only the original headers were returned in the text/rfc822\-headers chunk, they'll be available here as a Mail::Header entity. .SS "orig_text" .IX Subsection "orig_text" If the bounce message was poorly structured, the above two methods won't return anything \-\-\- instead, you get back a block of text that may or may not approximate the original message. No guarantees. Good luck. .SH "CAVEATS" .IX Header "CAVEATS" Bounce messages are generally meant to be read by humans, not computers. A poorly formatted bounce message may fool BounceParser into spreading its net too widely and returning email addresses that didn't actually bounce. Before you do anything with the email addresses you get back, confirm that it makes sense that they might be bouncing \-\-\- for example, it doesn't make sense for the sender of the original message to show up in the addresses list, but it could if the bounce message is sufficiently misformatted. .PP Still, please report all bugs! .SH "FREE-FLOATING ANXIETY" .IX Header "FREE-FLOATING ANXIETY" Some bizarre MTAs construct bounce messages using the original headers of the original message. If your application relies on the assumption that all Message-IDs are unique, you need to watch out for these MTAs and program defensively; before doing anything with the Message-ID of a bounce message, first confirm that you haven't already seen it; if you have, change it to something else that you make up on the spot, such as \&\*(L"\*(R". .SH "BUGS" .IX Header "BUGS" BounceParser assumes a sanely constructed bounce message. Input from the real world may cause BounceParser to barf and die horribly when we violate one of MIME::Entity's assumptions; this is why you should always call it inside an eval { }. .SS "\s-1TODO\s0" .IX Subsection "TODO" Provide some translation of the \s-1SMTP\s0 and \s-1DSN\s0 error codes into English. Review \&\s-1RFC1891\s0 and \s-1RFC1893.\s0 .SH "KNOWN TO WORK WITH" .IX Header "KNOWN TO WORK WITH" We understand bounce messages generated by the following MTAs / organizations: .PP .Vb 10 \& Postfix \& Sendmail \& Exim \& AOL \& Yahoo \& Hotmail \& AOL\*(Aqs AirMail sender\-blocking \& Microsoft Exchange* \& Qmail* \& Novell Groupwise* \& \& * Items marked with an asterisk currently may return incomplete information. .Ve .SH "SEE ALSO" .IX Header "SEE ALSO" .Vb 2 \& Used by http://listbox.com/ \-\-\- if you like BounceParser and you know it, \& consider Listbox for your mailing list needs! \& \& SVN repository and email list information at: \& http://emailproject.perl.org/ \& \& RFC1892 and RFC1894 .Ve .SH "RANDOM OBSERVATION" .IX Header "RANDOM OBSERVATION" Schwern's modules have the Alexandre Dumas property. .SH "AUTHOR" .IX Header "AUTHOR" Original author: Meng Weng Wong, .PP Current maintainer: Ricardo \s-1SIGNES,\s0 .PP Massive contributions to the 1.5xx series were made by William Yardley and Michael Stevens. Ricardo mostly just helped out and managed releases. .SH "COPYRIGHT AND LICENSE" .IX Header "COPYRIGHT AND LICENSE" .Vb 3 \& Copyright (C) 2003\-2006, IC Group, Inc. \& pobox.com permanent email forwarding with spam filtering \& listbox.com mailing list services for announcements and discussion .Ve .PP This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. .SH "WITH A SHOUT OUT TO" .IX Header "WITH A SHOUT OUT TO" .Vb 2 \& coraline, Fletch, TorgoX, mjd, a\-mused, Masque, gbarr, \& sungo, dngor, and all the other hoopy froods on #perl .Ve