From 165ce061bbcd3c65c5d7a52bfea2605f58d94083 Mon Sep 17 00:00:00 2001
From: Richard Bairwell ". $status_code_classes[$arr[0]]['title'] . " - " .$status_code_classes[$arr[0]]['descr']. " ". $status_code_subclasses[$arr[1].".".$arr[2]]['title'] . " - " .$status_code_subclasses[$arr[1].".".$arr[2]]['descr']. " " . $status_code_classes[$arr[0]]['title'] . " - " .
+ $status_code_classes[$arr[0]]['descr'] . " " . $status_code_subclasses[$arr[1] . "." .
+ $arr[2]]['title'] . " - " . $status_code_subclasses[$arr[1] . "." . $arr[2]]['descr'] . " File Tests: File Tests:
Chris Fortune ~ http://cfortune.kics.bc.ca
June 19, 2014
-July 4, 2013
-
-Replaced deprecated split() function.
-Added auto-responder identification filter.
-Suppressed php Notice errors.
-
-
+ July 4, 2013
+
+ Replaced deprecated split() function.
+ Added auto-responder identification filter.
+ Suppressed php Notice errors.
+
+
+
-Feb 3, 2011
-
-Hey! Class is no longer static, it is rewritten in dynamic
-
+ Feb 3, 2011
+
-This bounce handler Attempts to parse Multipart reports for hard bounces, according to RFC1892 (RFC 1892 - The Multipart/Report Content Type for the Reporting of Mail System Administrative Messages) and RFC1894 (RFC 1894 - An Extensible Message Format for Delivery Status Notifications). We can reuse this for any well-formed bounces.
-It handles FBL (Feedback Loop) emails, if they are in Abuse Feedback Reporting Format, ARF (It even handles Hotmail's ridiculous attempts at FBL). DKIM parsing is not yet implemented.
-
-You can configure custom regular expressions to find any web beacons you may have put in your outgoing mails, in either the mail body or an x-header field. (see source code for examples). You can use it to track data (eg, recipient, list, mail run, etc...) by sending out unique ids, then parsing them from the bounces. This is especially useful when parsing FBL's, because usually all recipient fields have been removed (redacted).
-
-If the bounce is not well formed, it tries to extract some useful information anyway. Currently Postfix and Exim are supported, partially. You can edit the function ".$_GET['eml']." -- ";
- echo "View a different bounce Quick and dirty bounce handler:
+ Hey! Class is no longer static, it is rewritten in dynamic
+
+ This bounce handler Attempts to parse Multipart reports for hard bounces, according to RFC1892 (RFC 1892 - The Multipart/Report Content Type for
+ the Reporting of Mail System Administrative Messages) and RFC1894
+ (RFC 1894 - An Extensible Message Format for Delivery Status Notifications). We can reuse this for any
+ well-formed bounces.
+ It handles FBL (Feedback Loop) emails, if they are in Abuse Feedback Reporting Format, ARF
+ (It even handles Hotmail's ridiculous attempts at FBL). DKIM parsing is not yet implemented.
+
+ You can configure custom regular expressions to find any web beacons you may have put in your outgoing mails, in
+ either the mail body or an x-header field. (see source code for examples). You can use it to track data (eg,
+ recipient, list, mail run, etc...) by sending out unique ids, then parsing them from the bounces. This is
+ especially useful when parsing FBL's, because usually all recipient fields have been removed (redacted).
+
+ If the bounce is not well formed, it tries to extract some useful information anyway. Currently Postfix and Exim
+ are supported, partially. You can edit the function " . $_GET['eml'] . " -- ";
+ echo "View a different bounce Quick and dirty bounce handler: ";
- $multiArray = $bouncehandler->get_the_facts($bounce);
- echo "";
- $files = get_sorted_file_list('eml');
- if (is_array($files)) {
- reset($files);
- echo " Files: Files: Will return recipient's email address, the RFC1893 error code, and the action. Action can be one of the following:
+ echo " Will return recipient's email address, the RFC1893 error code, and the action. Action can be one of the following:
You could dereference the \$multiArray in a 'for loop', for example... You could dereference the \$multiArray in a 'for loop', for example... That's all you need to know, but if you want to get more complicated you can. All methods are public. See source code. That's all you need to know, but if you want to get more complicated you can. All methods are public. See source code. Postfix adds an appropriate X- header (X-Postfix-Sender:), so you do not need to create one via phpmailer. RFC's call for an optional Original-recipient field, but mandatory Final-recipient field is a fair substitute. Postfix adds an appropriate X- header (X-Postfix-Sender:), so you do not need to create one via phpmailer. RFC's call for an optional Original-recipient field, but mandatory Final-recipient field is a fair substitute. It's all in the status code, if you can find one. Report #" . ($i + 1) . "
+ /**
+ * @var string
+ */
public $web_beacon_preg_1 = "";
+ /**
+ * @var string
+ */
public $web_beacon_preg_2 = "";
+ /**
+ * @var string
+ */
public $x_header_search_1 = "";
- public $x_header_search_2 = "";
- // accessors
+ // these are for feedback reports, so you can extract uids from the emails
+ // eg X-my-custom-header: userId12345
+ // eg
+ /**
+ * @var string
+ */
+ public $x_header_search_2 = "";
+ /**
+ * @var string
+ */
public $type = "";
+ /**
+ * @var string
+ */
public $web_beacon_1 = "";
+ /**
+ * @var string
+ */
public $web_beacon_2 = "";
+
+ // accessors
+ /**
+ * @var string
+ */
public $feedback_type = "";
+ /**
+ * @var string
+ */
public $x_header_beacon_1 = "";
+ /**
+ * @var string
+ */
public $x_header_beacon_2 = "";
-
- // these accessors are useful only for FBL's
- // or if the output array has only one index
+ /**
+ * @var string
+ */
public $action = "";
+ /**
+ * @var string
+ */
public $status = "";
+ /**
+ * @var string
+ */
public $subject = "";
+
+ // these accessors are useful only for FBL's
+ // or if the output array has only one index
+ /**
+ * @var string
+ */
public $recipient = "";
+ /**
+ * @var array
+ */
+ public $output = array();
+ /**
+ * @var array
+ */
+ private $bouncelist = array();
+ /**
+ * @var array
+ */
+ private $autorespondlist = array();
// the raw data set, a multiArray
- public $output = array();
+ /**
+ * @var array
+ */
+ private $bouncesubj = array();
-
- /**** INSTANTIATION *******************************************************/
- public function __construct(){
- $this->output[0]['action'] = "";
- $this->output[0]['status'] = "";
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ $this->output[0]['action'] = "";
+ $this->output[0]['status'] = "";
$this->output[0]['recipient'] = "";
- require('bounce_responses.php');
+ require_once('bounce_responses.php');
$this->bouncelist = $bouncelist;
$this->autorespondlist = $autorespondlist;
$this->bouncesubj = $bouncesubj;
}
-
+
/**** METHODS *************************************************************/
- // this is the most commonly used public method
- // quick and dirty
- // useage: $multiArray = $this->get_the_facts($strEmail);
- public function parse_email($eml){
+ //
+ /**
+ * This is the most commonly used public method - quick and dirty email parsing.
+ *
+ * Usage: $multiArray = $this->get_the_facts($strEmail);
+ *
+ * @param string $eml
+ *
+ * @return array
+ */
+ public function parse_email($eml)
+ {
return $this->get_the_facts($eml);
}
- public function get_the_facts($eml){
+
+ /**
+ * Gets the facts about the email
+ * @param string $eml
+ *
+ * @return array
+ */
+ public function get_the_facts($eml)
+ {
// fluff up the email
$bounce = $this->init_bouncehandler($eml);
- if (strpos($bounce, "\r\n\r\n") !== FALSE)
+ if (strpos($bounce, "\r\n\r\n") !== false) {
list($head, $body) = preg_split("/\r\n\r\n/", $bounce, 2);
- else
+ } else {
list($head, $body) = array($bounce, '');
+ }
$this->head_hash = $this->parse_head($head);
// parse the email into data structures
@@ -113,7 +208,7 @@ public function get_the_facts($eml){
$this->looks_like_a_bounce = $this->is_a_bounce();
$this->looks_like_an_FBL = $this->is_an_ARF();
$this->looks_like_an_autoresponse = !$this->looks_like_a_bounce && !$this->looks_like_an_FBL && $this->is_an_autoresponse();
-
+
/* If you are trying to save processing power, and don't care much
* about accuracy then uncomment this statement in order to skip the
* heroic text parsing below.
@@ -125,13 +220,15 @@ public function get_the_facts($eml){
/*** now we try all our weird text parsing methods (E-mail is weird!) ******************************/
- // is it a Feedback Loop, in Abuse Feedback Reporting Format (ARF)?
- // http://en.wikipedia.org/wiki/Abuse_Reporting_Format#Abuse_Feedback_Reporting_Format_.28ARF.29
- if($this->looks_like_an_FBL){
+ /**
+ * Is it a feedback loop in abuse feedback reporting format (ARF)?
+ * @see http://en.wikipedia.org/wiki/Abuse_Reporting_Format#Abuse_Feedback_Reporting_Format_.28ARF.29
+ */
+ if ($this->looks_like_an_FBL) {
$this->output[0]['action'] = 'failed';
$this->output[0]['status'] = "5.7.1";
$this->subject = trim(str_ireplace("Fw:", "", $this->head_hash['Subject']));
- if ($this->is_hotmail_fbl === true){
+ if ($this->is_hotmail_fbl === true) {
// fill in the fbl_hash with sensible values
$this->fbl_hash['Source-ip'] = '';
$this->fbl_hash['Original-mail-from'] = '';
@@ -140,52 +237,63 @@ public function get_the_facts($eml){
$this->fbl_hash['Content-disposition'] = 'inline';
$this->fbl_hash['Content-type'] = 'message/feedback-report';
$this->fbl_hash['User-agent'] = 'Hotmail FBL';
- if (isset($this->first_body_hash['Date']))
+ if (isset($this->first_body_hash['Date'])) {
$this->fbl_hash['Received-date'] = $this->first_body_hash['Date'];
- if (isset($this->head_hash['Subject']) && preg_match('/complaint about message from ([0-9.]+)/', $this->head_hash['Subject'], $matches))
+ }
+ if (isset($this->head_hash['Subject']) && preg_match('/complaint about message from ([0-9.]+)/',
+ $this->head_hash['Subject'], $matches)
+ ) {
$this->fbl_hash['Source-ip'] = $matches[1];
- if (!empty($this->recipient))
+ }
+ if (!empty($this->recipient)) {
$this->fbl_hash['Original-rcpt-to'] = $this->recipient;
- if (isset($this->first_body_hash['X-sid-pra']))
+ }
+ if (isset($this->first_body_hash['X-sid-pra'])) {
$this->fbl_hash['Original-mail-from'] = $this->first_body_hash['X-sid-pra'];
- }
- else {
+ }
+ } else {
$this->fbl_hash = $this->standard_parser($mime_sections['machine_parsable_body_part']);
$returnedhash = $this->standard_parser($mime_sections['returned_message_body_part']);
- if (!empty($returnedhash['Return-path']))
+ if (!empty($returnedhash['Return-path'])) {
$this->fbl_hash['Original-mail-from'] = $returnedhash['Return-path'];
- elseif (empty($this->fbl_hash['Original-mail-from']) && !empty($returnedhash['From']))
+ } elseif (empty($this->fbl_hash['Original-mail-from']) && !empty($returnedhash['From'])) {
$this->fbl_hash['Original-mail-from'] = $returnedhash['From'];
- if (empty($this->fbl_hash['Original-rcpt-to']) && !empty($this->fbl_hash['Removal-recipient']) )
+ }
+ if (empty($this->fbl_hash['Original-rcpt-to']) && !empty($this->fbl_hash['Removal-recipient'])) {
$this->fbl_hash['Original-rcpt-to'] = $this->fbl_hash['Removal-recipient'];
- elseif (isset($returnedhash['To']))
+ } elseif (isset($returnedhash['To'])) {
$this->fbl_hash['Original-rcpt-to'] = $returnedhash['To'];
- else
+ } else {
$this->fbl_hash['Original-rcpt-to'] = '';
- if (!isset($this->fbl_hash['Source-ip']))
- if (!empty($returnedhash['X-originating-ip']))
+ }
+ if (!isset($this->fbl_hash['Source-ip'])) {
+ if (!empty($returnedhash['X-originating-ip'])) {
$this->fbl_hash['Source-ip'] = $this->strip_angle_brackets($returnedhash['X-originating-ip']);
- else
+ } else {
$this->fbl_hash['Source-ip'] = '';
+ }
+ }
}
// warning, some servers will remove the name of the original intended recipient from the FBL report,
// replacing it with redacted@rcpt-hostname.com, making it utterly useless, of course (unless you used a web-beacon).
// here we try our best to give you the actual intended recipient, if possible.
- if (preg_match('/Undisclosed|redacted/i', $this->fbl_hash['Original-rcpt-to']) && isset($this->fbl_hash['Removal-recipient']) ) {
+ if (preg_match('/Undisclosed|redacted/i',
+ $this->fbl_hash['Original-rcpt-to']) && isset($this->fbl_hash['Removal-recipient'])
+ ) {
$this->fbl_hash['Original-rcpt-to'] = @$this->fbl_hash['Removal-recipient'];
}
- if (empty($this->fbl_hash['Received-date']) && !empty($this->fbl_hash[@'Arrival-date']) ) {
+ if (empty($this->fbl_hash['Received-date']) && !empty($this->fbl_hash[@'Arrival-date'])) {
$this->fbl_hash['Received-date'] = @$this->fbl_hash['Arrival-date'];
}
$this->fbl_hash['Original-mail-from'] = $this->strip_angle_brackets(@$this->fbl_hash['Original-mail-from']);
- $this->fbl_hash['Original-rcpt-to'] = $this->strip_angle_brackets(@$this->fbl_hash['Original-rcpt-to']);
+ $this->fbl_hash['Original-rcpt-to'] = $this->strip_angle_brackets(@$this->fbl_hash['Original-rcpt-to']);
$this->output[0]['recipient'] = $this->fbl_hash['Original-rcpt-to'];
}
-#??? else if (preg_match("/auto.{0,20}reply|vacation|(out|away|on holiday).*office/i", $this->head_hash['Subject'])){
-# // looks like a vacation autoreply, ignoring
-# $this->output[0]['action'] = 'autoreply';
-# }
+ #??? else if (preg_match("/auto.{0,20}reply|vacation|(out|away|on holiday).*office/i", $this->head_hash['Subject'])){
+ # // looks like a vacation autoreply, ignoring
+ # $this->output[0]['action'] = 'autoreply';
+ # }
// is this an autoresponse ?
elseif ($this->looks_like_an_autoresponse) {
@@ -193,76 +301,67 @@ public function get_the_facts($eml){
$this->output[0]['autoresponse'] = $this->autoresponse; #??? 4.3.2
// grab the first recipient and break
$this->output[0]['recipient'] = isset($this->head_hash['Return-path']) ? $this->strip_angle_brackets($this->head_hash['Return-path']) : '';
- if(empty($this->output[0]['recipient'])){
+ if (empty($this->output[0]['recipient'])) {
$arrFailed = $this->find_email_addresses($body);
- for($j=0; $j
\n";
- }
- else{
+ } else {
print " - WRONG
\n";
print "\n";
print_r($multiArray[0]);
print "\n";
}
- }
+ }
}
}
?>
@@ -36,69 +36,92 @@
-
+
-Download source code
-
+ Download source code
+
-$this-> notation. It's much easier to customize now. If you are upgrading from a previous version, you will need to rewrite your method invocation code.
-
-
-Download source code
-
+ get_the_facts() if you want to add a parser for your own busted MTA. Please forward any useful & reuseable code to the keeper of this class. Chris Fortune
+ $this-> notation. It's much easier to
+ customize now. If you are upgrading from a previous version, you will need to rewrite your method invocation
+ code.
+
+
+
+ Download source code
+
+
+ get_the_facts() if you want to add a parser for
+ your own busted MTA. Please forward any useful & reuseable code to the keeper of this class. Chris Fortune
useage:
require_once(\"bounce_driver.class.php\");
@@ -110,39 +133,38 @@
print_r(\$multiArray);
\n";
+ $bounce = $bouncehandler->init_bouncehandler($bounce, 'string');
+ list($head, $body) = preg_split("/\r\n\r\n/", $bounce, 2);
+ } else {
+ print "
\n";
+
+ $files = get_sorted_file_list('eml');
+ if (is_array($files)) {
+ reset($files);
+ echo "
\n";
+ }
}
+ exit;
}
- exit;
-}
-echo "
";
-echo "
foreach(\$multiArray as \$the){
switch(\$the['action']){
@@ -194,111 +216,112 @@
";
-echo "
";
+ echo "
";
-echo "Here is the parsed head
\n";
-$head_hash = $bouncehandler->parse_head($head);
-echo "Here is the parsed head
\n";
+ $head_hash = $bouncehandler->parse_head($head);
+ echo "Looks like an RFC1892 multipart report
";
-}
-else if($bouncehandler->looks_like_an_FBL){
- print "It's a Feedback Loop, ";
- if($bouncehandler->is_hotmail_fbl){
- print " in Hotmail Doofus Format (HDF?)
";
- }else{
- print " in Abuse Feedback Reporting format (ARF)";
- echo "Looks like an RFC1892 multipart report
";
+ } else if ($bouncehandler->looks_like_an_FBL) {
+ print "It's a Feedback Loop, ";
+ if ($bouncehandler->is_hotmail_fbl) {
+ print " in Hotmail Doofus Format (HDF?)
";
+ } else {
+ print " in Abuse Feedback Reporting format (ARF)";
+ echo "Not an RFC1892 multipart report
";
+ echo "Not an RFC1892 multipart report
";
- echo "Here is the parsed report
\n";
+ echo "Here is the parsed report
\n";
-echo "Here is the error status code
\n";
+ echo "
\n";
+ echo $bouncehandler->find_recipient($rpt_hash['per_recipient'][$i]);
+ $scode = $rpt_hash['per_recipient'][$i]['Status'];
+ echo "$scode
";
+ echo $bouncehandler->fetch_status_messages($scode);
+ echo "
is not the same as the reported status code, but it seems to be more descriptive, so it should be extracted (if possible)."; + for ($i = 0; $i < count($rpt_hash['per_recipient']); $i++) { + echo "
Report #" . ($i + 1) . "
\n";
+ echo $bouncehandler->find_recipient($rpt_hash['per_recipient'][$i]);
+ $dcode = $rpt_hash['per_recipient'][$i]['Diagnostic-code']['text'];
+ if ($dcode) {
+ echo "
$dcode"; + echo $bouncehandler->fetch_status_messages($dcode); + } else { + echo "
couldn't decode"; + } + echo "\n"; + } + echo "
Just in case we don't have an Original-recipient: field, or a X-Postfix-Sender: field, we can retrieve information from the (optional) returned message body part
\n"; + $head = $bouncehandler->get_head_from_returned_message_body_part($mime_sections); + echo "From: " . $head['From'] . "
To: " . $head['To'] . "
Subject: " . $head['Subject'] . "
It's all in the status code, if you can find one.
"; -for($i=0; $i$scode"; - echo $bouncehandler->fetch_status_messages($scode); - echo "\n"; -} -echo "
is not the same as the reported status code, but it seems to be more descriptive, so it should be extracted (if possible).";
-for($i=0; $i
\n";
- echo $bouncehandler->find_recipient($rpt_hash['per_recipient'][$i]);
- $dcode = $rpt_hash['per_recipient'][$i]['Diagnostic-code']['text'];
- if($dcode){
- echo "$dcode
";
- echo $bouncehandler->fetch_status_messages($dcode);
- }
- else{
- echo "couldn't decode
";
- }
- echo "
Three parts: [first_body_part], [machine_parsable_body_part], and [returned_message_body_part]
"; + echo "Just in case we don't have an Original-recipient: field, or a X-Postfix-Sender: field, we can retrieve information from the (optional) returned message body part
\n"; -$head = $bouncehandler->get_head_from_returned_message_body_part($mime_sections); -echo "From: ".$head['From']."
To: ".$head['To']."
Subject: ".$head['Subject']."
Three parts: [first_body_part], [machine_parsable_body_part], and [returned_message_body_part]
"; -echo "" . $status_code_classes[$arr[0]]['title'] . " - " . - $status_code_classes[$arr[0]]['descr'] . " " . $status_code_subclasses[$arr[1] . "." . - $arr[2]]['title'] . " - " . $status_code_subclasses[$arr[1] . "." . $arr[2]]['descr'] . "
"; + $str = "" . $code_classes[ $arr[0] ]['title'] . " - " . + $code_classes[ $arr[0] ]['descr'] . " " . + $sub_classes[ $arr[1] . "." .$arr[2] ]['title'] . + " - " . $sub_classes[ $arr[1] . "." . $arr[2] ]['descr'] . "
"; + return $str; } - - /*The syntax of the final-recipient field is as follows: - "Final-Recipient" ":" address-type ";" generic-address - */ - - /** - * @param $fbl - * - * @return string - */ - private function find_fbl_recipients($fbl) - { - if (isset($fbl['Original-rcpt-to'])) { - return $fbl['Original-rcpt-to']; - } else if (isset($fbl['Removal-recipient'])) { - return trim(str_replace('--', '', $fbl['Removal-recipient'])); - } - } } /** END class BounceHandler **/ \ No newline at end of file From 194c84a18da249731331cac512f77b0f44d03363 Mon Sep 17 00:00:00 2001 From: Richard Bairwell\n";
- print_r($multiArray[0]);
+ print_r($multiArray);
print "\n";
+ print htmlspecialchars(print_r($bouncehandler->output,true));
}
}
}
}
-?>
-
-- Chris Fortune ~ http://cfortune.kics.bc.ca -
- -June 19, 2014
-- July 4, 2013 -
- -- Replaced deprecated split() function. - Added auto-responder identification filter. - Suppressed php Notice errors. - -
-
- Feb 3, 2011 -
- -
- Hey! Class is no longer static, it is rewritten in dynamic $this-> notation. It's much easier to
- customize now. If you are upgrading from a previous version, you will need to rewrite your method invocation
- code.
-
-
-
- This bounce handler Attempts to parse Multipart reports for hard bounces, according to RFC1892 (RFC 1892 - The Multipart/Report Content Type for - the Reporting of Mail System Administrative Messages) and RFC1894 - (RFC 1894 - An Extensible Message Format for Delivery Status Notifications). We can reuse this for any - well-formed bounces.
- -- It handles FBL (Feedback Loop) emails, if they are in Abuse Feedback Reporting Format, ARF - (It even handles Hotmail's ridiculous attempts at FBL). DKIM parsing is not yet implemented. -
- -- You can configure custom regular expressions to find any web beacons you may have put in your outgoing mails, in - either the mail body or an x-header field. (see source code for examples). You can use it to track data (eg, - recipient, list, mail run, etc...) by sending out unique ids, then parsing them from the bounces. This is - especially useful when parsing FBL's, because usually all recipient fields have been removed (redacted). -
- -
- If the bounce is not well formed, it tries to extract some useful information anyway. Currently Postfix and Exim
- are supported, partially. You can edit the function get_the_facts() if you want to add a parser for
- your own busted MTA. Please forward any useful & reuseable code to the keeper of this class. Chris Fortune
" . $_GET['eml'] . " -- "; - echo "View a different bounce
"; - $bounce = file_get_contents("eml/" . $_GET['eml']); - echo "Quick and dirty bounce handler:
+if (isset($_GET['eml'])) {
+ echo "
" . $_GET['eml'] . " -- "; + echo "View a different bounce
"; + $bounce = file_get_contents("eml/" . $_GET['eml']); + echo "Quick and dirty bounce handler:
useage:
require_once(\"bounce_driver.class.php\");
@@ -133,38 +65,38 @@
print_r(\$multiArray);
";
- $multiArray = $bouncehandler->get_the_facts($bounce);
- echo "";
- //print_r($bouncehandler); exit;
+ $multiArray = $bouncehandler->get_the_facts($bounce);
+ echo "";
+ //print_r($bouncehandler); exit;
- print_r($multiArray);
- echo " ";
+ print_r($multiArray);
+ echo " ";
- $bounce = $bouncehandler->init_bouncehandler($bounce, 'string');
- list($head, $body) = preg_split("/\r\n\r\n/", $bounce, 2);
- } else {
- print "
- Test All Sample Bounce E-mails\n\n";
- print "
- Or, select a bounce email to view the parsed results:
\n";
+ $bounce = $bouncehandler->init_bouncehandler($bounce, 'string');
+ list($head, $body) = preg_split("/\r\n\r\n/", $bounce, 2);
+} else {
+ print "- Test All Sample Bounce E-mails\n\n";
+ print "
- Or, select a bounce email to view the parsed results:
\n";
- $files = get_sorted_file_list('eml');
- if (is_array($files)) {
- reset($files);
- echo "Files:
\n";
- foreach ($files as $file) {
- echo "$file
\n";
- }
+ $files = get_sorted_file_list('eml');
+ if (is_array($files)) {
+ reset($files);
+ echo "Files:
\n";
+ foreach ($files as $file) {
+ echo "$file
\n";
}
- exit;
}
+ exit;
+}
- echo "Will return recipient's email address, the RFC1893 error code, and the action. Action can be one of the following:
+echo "
Will return recipient's email address, the RFC1893 error code, and the action. Action can be one of the following:
- 'transient'(temporary problem),
- 'failed' (permanent problem),
-
- 'autoreply' (a vacation auto-response), or
+
- 'autoresponse' (a vacation auto-response), or
- '' (nothing -- not classified).
";
- echo "You could dereference the \$multiArray in a 'for loop', for example...
+echo "You could dereference the \$multiArray in a 'for loop', for example...
foreach(\$multiArray as \$the){
switch(\$the['action']){
@@ -182,7 +114,7 @@
insert_into_queue(\$the['recipient'], (\$num_attempts+1));
}
break;
- case 'autoreply':
+ case 'autoresponse':
//do something different
postpone(\$the['recipient'], '7 days');
break;
@@ -216,112 +148,89 @@
";
- echo "That's all you need to know, but if you want to get more complicated you can. All methods are public. See source code.
";
+echo "That's all you need to know, but if you want to get more complicated you can. All methods are public. See source code.
";
- echo "
Here is the parsed head
\n";
- $head_hash = $bouncehandler->parse_head($head);
- echo "";
- print_r($head_hash);
- echo " ";
+echo "
Here is the parsed head
\n";
+$head_hash = $bouncehandler->parse_head($head);
+echo "";
+print_r($head_hash);
+echo " ";
+if ($bouncehandler->is_RFC1892_multipart_report($head_hash)) {
+ print "Looks like an RFC1892 multipart report
";
+} else if ($bouncehandler->looks_like_an_FBL) {
+ print "It's a Feedback Loop, ";
if ($bouncehandler->is_hotmail_fbl) {
- echo "RRRRRR" . $bouncehandler->recipient;
- }
- exit;
-
- if ($bouncehandler->is_RFC1892_multipart_report($head_hash)) {
- print "Looks like an RFC1892 multipart report
";
- } else if ($bouncehandler->looks_like_an_FBL) {
- print "It's a Feedback Loop, ";
- if ($bouncehandler->is_hotmail_fbl) {
- print " in Hotmail Doofus Format (HDF?)
";
- } else {
- print " in Abuse Feedback Reporting format (ARF)
";
- echo "";
- print_r($bouncehandler->fbl_hash);
- echo " ";
- }
+ print " in Hotmail Doofus Format (HDF?)";
} else {
- print "Not an RFC1892 multipart report
";
- echo "";
- print_r($body);
+ print " in Abuse Feedback Reporting format (ARF)";
+ echo "";
+ print_r($bouncehandler->fbl_hash);
echo " ";
- exit;
}
-
-
- echo "Here is the parsed report
\n";
- echo "Postfix adds an appropriate X- header (X-Postfix-Sender:), so you do not need to create one via phpmailer. RFC's call for an optional Original-recipient field, but mandatory Final-recipient field is a fair substitute.
";
- $boundary = $head_hash['Content-type']['boundary'];
- $mime_sections = $bouncehandler->parse_body_into_mime_sections($body, $boundary);
- $rpt_hash = $bouncehandler->parse_machine_parsable_body_part($mime_sections['machine_parsable_body_part']);
- echo "";
- print_r($rpt_hash);
+} else {
+ print "Not an RFC1892 multipart report
";
+ echo "";
+ print_r($body);
echo " ";
+ exit;
+}
- echo "Here is the error status code
\n";
- echo "It's all in the status code, if you can find one.
";
- for ($i = 0; $i < count($rpt_hash['per_recipient']); $i++) {
- echo "Report #" . ($i + 1) . "
\n";
- echo $bouncehandler->find_recipient($rpt_hash['per_recipient'][$i]);
- $scode = $rpt_hash['per_recipient'][$i]['Status'];
- echo "
$scode
";
- echo $bouncehandler->fetch_status_messages($scode);
- echo "\n";
- }
+echo "Here is the parsed report
\n";
+echo "Postfix adds an appropriate X- header (X-Postfix-Sender:), so you do not need to create one via phpmailer. RFC's call for an optional Original-recipient field, but mandatory Final-recipient field is a fair substitute.
";
+$boundary = $head_hash['Content-type']['boundary'];
+$mime_sections = $bouncehandler->parse_body_into_mime_sections($body, $boundary);
+$rpt_hash = $bouncehandler->parse_machine_parsable_body_part($mime_sections['machine_parsable_body_part']);
+echo "";
+print_r($rpt_hash);
+echo " ";
+
+
+echo "Here is the error status code
\n";
+echo "It's all in the status code, if you can find one.
";
+for ($i = 0; $i < count($rpt_hash['per_recipient']); $i++) {
+ echo "Report #" . ($i + 1) . "
\n";
+ echo $bouncehandler->find_recipient($rpt_hash['per_recipient'][$i]);
+ $scode = $rpt_hash['per_recipient'][$i]['Status'];
+ echo "
$scode
";
+ echo $bouncehandler->fetch_status_messages($scode);
+ echo "\n";
+}
- echo "The Diagnostic-code
is not the same as the reported status code, but it seems to be more descriptive, so it should be extracted (if possible).";
- for ($i = 0; $i < count($rpt_hash['per_recipient']); $i++) {
- echo "
Report #" . ($i + 1) . "
\n";
- echo $bouncehandler->find_recipient($rpt_hash['per_recipient'][$i]);
- $dcode = $rpt_hash['per_recipient'][$i]['Diagnostic-code']['text'];
- if ($dcode) {
- echo "
$dcode
";
- echo $bouncehandler->fetch_status_messages($dcode);
- } else {
- echo "couldn't decode
";
- }
- echo "\n";
+echo "The Diagnostic-code
is not the same as the reported status code, but it seems to be more descriptive, so it should be extracted (if possible).";
+for ($i = 0; $i < count($rpt_hash['per_recipient']); $i++) {
+ echo "
Report #" . ($i + 1) . "
\n";
+ echo $bouncehandler->find_recipient($rpt_hash['per_recipient'][$i]);
+ $dcode = $rpt_hash['per_recipient'][$i]['Diagnostic-code']['text'];
+ if ($dcode) {
+ echo "
$dcode
";
+ echo $bouncehandler->fetch_status_messages($dcode);
+ } else {
+ echo "couldn't decode
";
}
+ echo "\n";
+}
- echo "Grab original To: and From:
\n";
- echo "Just in case we don't have an Original-recipient: field, or a X-Postfix-Sender: field, we can retrieve information from the (optional) returned message body part
\n";
- $head = $bouncehandler->get_head_from_returned_message_body_part($mime_sections);
- echo "From: " . $head['From'] . "
To: " . $head['To'] . "
Subject: " . $head['Subject'] . "
";
-
+echo "Grab original To: and From:
\n";
+echo "Just in case we don't have an Original-recipient: field, or a X-Postfix-Sender: field, we can retrieve information from the (optional) returned message body part
\n";
+$head = $bouncehandler->get_head_from_returned_message_body_part($mime_sections);
+echo "From: " . $head['From'] . "
To: " . $head['To'] . "
Subject: " . $head['Subject'] . "
";
- echo "Here is the body in RFC1892 parts
\n";
- echo "Three parts: [first_body_part], [machine_parsable_body_part], and [returned_message_body_part]
";
- echo "";
- print_r($mime_sections);
- echo " ";
+echo "Here is the body in RFC1892 parts
\n";
+echo "Three parts: [first_body_part], [machine_parsable_body_part], and [returned_message_body_part]
";
+echo "";
+print_r($mime_sections);
+echo " ";
- /*
- $status_code = $bouncehandler->format_status_code($rpt_hash['per_recipient'][$i]['Status']);
- $status_code_msg = $bouncehandler->fetch_status_messages($status_code['code']);
- $status_code_remote_msg = $status_code['text'];
- $diag_code = $bouncehandler->format_status_code($rpt_hash['per_recipient'][$i]['Diagnostic-code']['text']);
- $diag_code_msg = $bouncehandler->fetch_status_messages($diag_code['code']);
- $diag_code_remote_msg = $diag_code['text'];
- */
-
- function get_sorted_file_list($d)
- {
- $fs = array();
- if ($h = opendir($d)) {
- while (false !== ($f = readdir($h))) {
- if ($f == '.' || $f == '..') {
- continue;
- }
- $fs[] = $f;
- }
- closedir($h);
- sort($fs, SORT_STRING);//
- }
- return $fs;
- }
- ?>
+/*
+ $status_code = $bouncehandler->format_status_code($rpt_hash['per_recipient'][$i]['Status']);
+ $status_code_msg = $bouncehandler->fetch_status_messages($status_code['code']);
+ $status_code_remote_msg = $status_code['text'];
+ $diag_code = $bouncehandler->format_status_code($rpt_hash['per_recipient'][$i]['Diagnostic-code']['text']);
+ $diag_code_msg = $bouncehandler->fetch_status_messages($diag_code['code']);
+ $diag_code_remote_msg = $diag_code['text'];
+*/
From 56516551042491048cc8483354ff816c3d4649d4 Mon Sep 17 00:00:00 2001
From: Richard Bairwell
Date: Tue, 16 Dec 2014 21:35:35 +0000
Subject: [PATCH 07/15] Fix email searching regular expression to handle less
common TLDs (longer than 4 characters or shorter than 2) and "odder" email
addresses
---
bounce_driver.class.php | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/bounce_driver.class.php b/bounce_driver.class.php
index 3565043..09e35af 100644
--- a/bounce_driver.class.php
+++ b/bounce_driver.class.php
@@ -878,10 +878,17 @@ private function strip_angle_brackets($recipient)
*/
function find_email_addresses($first_body_part)
{
- // not finished yet. This finds only one address.
- if (preg_match("/\b([A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4})\b/i", $first_body_part, $matches))
+ /**
+ * Regular expression for searching for email addresses
+ * @see https://bitbucket.org/bairwell/emailcheck/src/81c6a1a25d28a8abda1673ae1fbec3ba55b72bce/emailcheck.php?at=master
+ * Doesn't currently do any "likely domain valid" or similar checks
+ */
+ $regExp='/(?:[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/iS';
+
+ $matched=preg_match($regExp, $first_body_part, $matches);
+ if (1===$matched)
{
- return array($matches[1]);
+ return array($matches[0]);
}
else
{
From b654a5ef83353f671ce41c8f4dcb8f5d5a10f7c8 Mon Sep 17 00:00:00 2001
From: Richard Bairwell
Date: Mon, 22 Dec 2014 11:27:44 +0000
Subject: [PATCH 08/15] Made fully PEAR compliant with the help of the
PHPCodeSniffer
---
Make_statuscodes.php | 50 ++--
bounce_driver.class.php | 519 ++++++++++++++++---------------------
bounce_responses.php | 438 +++++++++++++++----------------
bounce_statuscodes.php | 150 +++++------
cmdlinetest.php | 6 +-
php.bouncehandler.v7.4.zip | Bin 317542 -> 0 bytes
testdriver1.php | 4 +-
7 files changed, 545 insertions(+), 622 deletions(-)
delete mode 100644 php.bouncehandler.v7.4.zip
diff --git a/Make_statuscodes.php b/Make_statuscodes.php
index f4d87a1..2bb2e37 100644
--- a/Make_statuscodes.php
+++ b/Make_statuscodes.php
@@ -1,7 +1,7 @@
5
- $a[1] = preg_replace('/\n\s*/', ' ', $a[1]); #remove line breaks
- $a[1] = preg_replace('/\s\s+/', ' ', $a[1]); #remove double spaces
- $a[1] = preg_replace('/"/', '\\"', $a[1]); #requote quotes
- $a[2] = preg_replace('/\n\s*/', ' ', $a[2]); #remove line breaks
- $a[2] = preg_replace('/\s\s+/', ' ', $a[2]); #remove double spaces
- $a[2] = preg_replace('/"/', '\\"', $a[2]); #requote quotes
+ $a[0] = preg_replace('/\..*/', '', $a[0]); // 5.x.x -> 5
+ $a[1] = preg_replace('/\n\s*/', ' ', $a[1]); // remove line breaks
+ $a[1] = preg_replace('/\s\s+/', ' ', $a[1]); // remove double spaces
+ $a[1] = preg_replace('/"/', '\\"', $a[1]); // requote quotes
+ $a[2] = preg_replace('/\n\s*/', ' ', $a[2]); // remove line breaks
+ $a[2] = preg_replace('/\s\s+/', ' ', $a[2]); // remove double spaces
+ $a[2] = preg_replace('/"/', '\\"', $a[2]); // requote quotes
print "\$status_code_classes['$a[0]']['title'] = \"" . $a[1] . "\"; # $a[3]\n";
print "\$status_code_classes['$a[0]']['descr'] = \"" . $a[2] . "\";\n";
}
@@ -29,26 +29,26 @@
print "\n";
-#X.7.17,Mailbox owner has changed,5XX,"This status code is returned when a message is
-#received with a Require-Recipient-Valid-Since
-#field or RRVS extension and the receiving
-#system is able to determine that the intended
-#recipient mailbox has not been under
-#continuous ownership since the specified date.",[RFC-ietf-appsawg-rrvs-header-field-10] (Standards Track),M. Kucherawy,IESG
+// X.7.17,Mailbox owner has changed,5XX,"This status code is returned when a message is
+// received with a Require-Recipient-Valid-Since
+// field or RRVS extension and the receiving
+// system is able to determine that the intended
+// recipient mailbox has not been under
+// continuous ownership since the specified date.",[RFC-ietf-appsawg-rrvs-header-field-10] (Standards Track),M. Kucherawy,IESG
$fh = fopen("http://www.iana.org/assignments/smtp-enhanced-status-codes/smtp-enhanced-status-codes-3.csv", "r");
if ($fh !== false) {
- $a = fgets($fh); # 1st line is titles
+ $a = fgets($fh); // 1st line is titles
while (!feof($fh)) {
$a = fgetcsv($fh, 0, ',', '"');
- $a[0] = preg_replace('/^X./i', '', $a[0]); #X.5.0 -> 5.0
- $a[1] = preg_replace('/\n\s*/', ' ', $a[1]); #remove line breaks
- $a[1] = preg_replace('/\s\s+/', ' ', $a[1]); #remove double spaces
- $a[1] = preg_replace('/"/', '\\"', $a[1]); #requote quotes
- $a[3] = preg_replace('/\n\s*/', ' ', $a[3]); #remove line breaks
- $a[3] = preg_replace('/\s\s+/', ' ', $a[3]); #remove double spaces
- $a[3] = preg_replace('/"/', '\\"', $a[3]); #requote quotes
+ $a[0] = preg_replace('/^X./i', '', $a[0]); // X.5.0 -> 5.0
+ $a[1] = preg_replace('/\n\s*/', ' ', $a[1]); // remove line breaks
+ $a[1] = preg_replace('/\s\s+/', ' ', $a[1]); // remove double spaces
+ $a[1] = preg_replace('/"/', '\\"', $a[1]); // requote quotes
+ $a[3] = preg_replace('/\n\s*/', ' ', $a[3]); // remove line breaks
+ $a[3] = preg_replace('/\s\s+/', ' ', $a[3]); // remove double spaces
+ $a[3] = preg_replace('/"/', '\\"', $a[3]); // requote quotes
print "\$status_code_subclasses['$a[0]']['title'] = \"" . $a[1] . "\"; # $a[4]\n";
print "\$status_code_subclasses['$a[0]']['descr'] = \"" . $a[3] . "\";\n";
}
diff --git a/bounce_driver.class.php b/bounce_driver.class.php
index 09e35af..409c096 100644
--- a/bounce_driver.class.php
+++ b/bounce_driver.class.php
@@ -32,23 +32,23 @@
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
- * @package BounceHandler
- * @author Chris Fortune http://cfortune.kics.bc.ca
- * @author Richard Bairwell - Code cleanups. http://blog.rac.me.uk
- * @author "Kanon"
- * @author Jamie McClelland http://mayfirst.org
- * @author Michael Cooper
- * @author Thomas Seifert
- * @author Tim Petrowsky http://neuecouch.de
- * @author Willy T. Koch http://apeland.no
- * @author ganeshaspeaks.com - FBL development
- * @author Richard Catto - FBL development
- * @author Scott Brynen - FBL development http://visioncritical.com
- * @copyright 2006-2014 Chris Fortune and others.
- * @license http://opensource.org/licenses/BSD-2-Clause BSD
- * @link http://www.anti-spam-man.com/php_bouncehandler/v7.3/
- * @link https://github.com/cfortune/PHP-Bounce-Handler/
- * @link http://www.phpclasses.org/browse/file/11665.html
+ * @package BounceHandler
+ * @author Chris Fortune http://cfortune.kics.bc.ca
+ * @author Richard Bairwell - Code cleanups. http://blog.rac.me.uk
+ * @author "Kanon"
+ * @author Jamie McClelland http://mayfirst.org
+ * @author Michael Cooper
+ * @author Thomas Seifert
+ * @author Tim Petrowsky http://neuecouch.de
+ * @author Willy T. Koch http://apeland.no
+ * @author ganeshaspeaks.com - FBL development
+ * @author Richard Catto - FBL development
+ * @author Scott Brynen - FBL development http://visioncritical.com
+ * @copyright 2006-2014 Chris Fortune and others.
+ * @license http://opensource.org/licenses/BSD-2-Clause BSD
+ * @link http://www.anti-spam-man.com/php_bouncehandler/v7.3/
+ * @link https://github.com/cfortune/PHP-Bounce-Handler/
+ * @link http://www.phpclasses.org/browse/file/11665.html
*/
/**
@@ -74,19 +74,19 @@ class BounceHandler
/**
* @var bool
*/
- public $looks_like_a_bounce = FALSE; // from bounce_responses
+ public $looks_like_a_bounce = false; // from bounce_responses
/**
* @var bool
*/
- public $looks_like_an_FBL = FALSE; // from bounce_responses
+ public $looks_like_an_FBL = false; // from bounce_responses
/**
* @var bool
*/
- public $looks_like_an_autoresponse = FALSE; // from bounce_responses
+ public $looks_like_an_autoresponse = false; // from bounce_responses
/**
* @var bool
*/
- public $is_hotmail_fbl = FALSE;
+ public $is_hotmail_fbl = false;
/**
* Regular expression to look for web beacons from emails.
*
@@ -209,9 +209,9 @@ class BounceHandler
*
* If bouncelist, autorespondlist or bouncesubj is empty, then load them in from the bounce_responses.php file
*
- * @param array $bouncelist text in messages from which to figure out what kind of bounc
+ * @param array $bouncelist text in messages from which to figure out what kind of bounc
* @param array $autorespondlist triggers for autoresponders
- * @param array $bouncesubj trigger subject lines for bounces
+ * @param array $bouncesubj trigger subject lines for bounces
*/
public function __construct($bouncelist=array(),$autorespondlist=array(),$bouncesubj=array())
{
@@ -222,7 +222,7 @@ public function __construct($bouncelist=array(),$autorespondlist=array(),$bounce
$this->autorespondlist = $autorespondlist;
$this->bouncesubj = $bouncesubj;
if (empty($bouncelist) || empty($autorespondlist) || empty($bouncesubj)) {
- require_once('bounce_responses.php');
+ include_once'bounce_responses.php';
if (empty($this->bouncelist)) {
$this->bouncelist = $bouncelist;
}
@@ -264,8 +264,7 @@ public function get_the_facts($eml)
{
// fluff up the email
$bounce = $this->init_bouncehandler($eml);
- if (strpos($bounce, "\r\n\r\n") !== FALSE)
- {
+ if (strpos($bounce, "\r\n\r\n") !== false) {
list($head, $body) = preg_split("/\r\n\r\n/", $bounce, 2);
}
else
@@ -299,13 +298,11 @@ public function get_the_facts($eml)
* Is it a feedback loop in abuse feedback reporting format (ARF)?
* @link http://en.wikipedia.org/wiki/Abuse_Reporting_Format#Abuse_Feedback_Reporting_Format_.28ARF.29
*/
- if ($this->looks_like_an_FBL)
- {
+ if ($this->looks_like_an_FBL) {
$this->output[0]['action'] = 'failed';
$this->output[0]['status'] = "5.7.1";
$this->subject = trim(str_ireplace("Fw:", "", $this->head_hash['Subject']));
- if ($this->is_hotmail_fbl === TRUE)
- {
+ if ($this->is_hotmail_fbl === true) {
// fill in the fbl_hash with sensible values
$this->fbl_hash['Source-ip'] = '';
$this->fbl_hash['Original-mail-from'] = '';
@@ -314,22 +311,20 @@ public function get_the_facts($eml)
$this->fbl_hash['Content-disposition'] = 'inline';
$this->fbl_hash['Content-type'] = 'message/feedback-report';
$this->fbl_hash['User-agent'] = 'Hotmail FBL';
- if (isset($this->first_body_hash['Date']))
- {
+ if (isset($this->first_body_hash['Date'])) {
$this->fbl_hash['Received-date'] = $this->first_body_hash['Date'];
}
- if (isset($this->head_hash['Subject']) && preg_match('/complaint about message from ([0-9.]+)/',
- $this->head_hash['Subject'], $matches)
+ if (isset($this->head_hash['Subject']) && preg_match(
+ '/complaint about message from ([0-9.]+)/',
+ $this->head_hash['Subject'], $matches
)
- {
+ ) {
$this->fbl_hash['Source-ip'] = $matches[1];
}
- if (!empty($this->recipient))
- {
+ if (!empty($this->recipient)) {
$this->fbl_hash['Original-rcpt-to'] = $this->recipient;
}
- if (isset($this->first_body_hash['X-sid-pra']))
- {
+ if (isset($this->first_body_hash['X-sid-pra'])) {
$this->fbl_hash['Original-mail-from'] = $this->first_body_hash['X-sid-pra'];
}
}
@@ -337,30 +332,24 @@ public function get_the_facts($eml)
{
$this->fbl_hash = $this->standard_parser($mime_sections['machine_parsable_body_part']);
$returnedhash = $this->standard_parser($mime_sections['returned_message_body_part']);
- if (!empty($returnedhash['Return-path']))
- {
+ if (!empty($returnedhash['Return-path'])) {
$this->fbl_hash['Original-mail-from'] = $returnedhash['Return-path'];
}
- elseif (empty($this->fbl_hash['Original-mail-from']) && !empty($returnedhash['From']))
- {
+ elseif (empty($this->fbl_hash['Original-mail-from']) && !empty($returnedhash['From'])) {
$this->fbl_hash['Original-mail-from'] = $returnedhash['From'];
}
- if (empty($this->fbl_hash['Original-rcpt-to']) && !empty($this->fbl_hash['Removal-recipient']))
- {
+ if (empty($this->fbl_hash['Original-rcpt-to']) && !empty($this->fbl_hash['Removal-recipient'])) {
$this->fbl_hash['Original-rcpt-to'] = $this->fbl_hash['Removal-recipient'];
}
- elseif (isset($returnedhash['To']))
- {
+ elseif (isset($returnedhash['To'])) {
$this->fbl_hash['Original-rcpt-to'] = $returnedhash['To'];
}
else
{
$this->fbl_hash['Original-rcpt-to'] = '';
}
- if (!isset($this->fbl_hash['Source-ip']))
- {
- if (!empty($returnedhash['X-originating-ip']))
- {
+ if (!isset($this->fbl_hash['Source-ip'])) {
+ if (!empty($returnedhash['X-originating-ip'])) {
$this->fbl_hash['Source-ip'] = $this->strip_angle_brackets($returnedhash['X-originating-ip']);
}
else
@@ -372,14 +361,14 @@ public function get_the_facts($eml)
// warning, some servers will remove the name of the original intended recipient from the FBL report,
// replacing it with redacted@rcpt-hostname.com, making it utterly useless, of course (unless you used a web-beacon).
// here we try our best to give you the actual intended recipient, if possible.
- if (preg_match('/Undisclosed|redacted/i',
- $this->fbl_hash['Original-rcpt-to']) && isset($this->fbl_hash['Removal-recipient'])
- )
- {
+ if (preg_match(
+ '/Undisclosed|redacted/i',
+ $this->fbl_hash['Original-rcpt-to']
+ ) && isset($this->fbl_hash['Removal-recipient'])
+ ) {
$this->fbl_hash['Original-rcpt-to'] = @$this->fbl_hash['Removal-recipient'];
}
- if (empty($this->fbl_hash['Received-date']) && !empty($this->fbl_hash[ @'Arrival-date' ]))
- {
+ if (empty($this->fbl_hash['Received-date']) && !empty($this->fbl_hash[ @'Arrival-date' ])) {
$this->fbl_hash['Received-date'] = @$this->fbl_hash['Arrival-date'];
}
$this->fbl_hash['Original-mail-from'] = $this->strip_angle_brackets(@$this->fbl_hash['Original-mail-from']);
@@ -387,22 +376,20 @@ public function get_the_facts($eml)
$this->output[0]['recipient'] = $this->fbl_hash['Original-rcpt-to'];
}
- #??? else if (preg_match("/auto.{0,20}reply|vacation|(out|away|on holiday).*office/i", $this->head_hash['Subject'])){
- # // looks like a vacation autoreply, ignoring
- # $this->output[0]['action'] = 'autoreply';
- # }
+ // ??? else if (preg_match("/auto.{0,20}reply|vacation|(out|away|on holiday).*office/i", $this->head_hash['Subject'])){
+ // // looks like a vacation autoreply, ignoring
+ // $this->output[0]['action'] = 'autoreply';
+ // }
// is this an autoresponse ?
- elseif ($this->looks_like_an_autoresponse)
- {
+ elseif ($this->looks_like_an_autoresponse) {
- $this->output[0]['action'] = 'autoresponse'; #??? 'transient' 'autoreply' ??
- $this->output[0]['autoresponse'] = $this->autoresponse; #??? 4.3.2
+ $this->output[0]['action'] = 'autoresponse'; // ??? 'transient' 'autoreply' ??
+ $this->output[0]['autoresponse'] = $this->autoresponse; // ??? 4.3.2
$this->output[0]['status']='2.0';
// grab the first recipient and break
$this->output[0]['recipient'] = isset($this->head_hash['Return-path']) ? $this->strip_angle_brackets($this->head_hash['Return-path']) : '';
- if (empty($this->output[0]['recipient']))
- {
+ if (empty($this->output[0]['recipient'])) {
$arrFailed = $this->find_email_addresses($body);
for ($j = 0; $j < count($arrFailed); $j++)
{
@@ -411,12 +398,10 @@ public function get_the_facts($eml)
}
}
}
- else if ($this->is_RFC1892_multipart_report() === TRUE)
- {
+ else if ($this->is_RFC1892_multipart_report() === true) {
$rpt_hash = $this->parse_machine_parsable_body_part($mime_sections['machine_parsable_body_part']);
- if (isset($rpt_hash['per_recipient']))
- {
+ if (isset($rpt_hash['per_recipient'])) {
for ($i = 0; $i < count($rpt_hash['per_recipient']); $i++)
{
$this->output[ $i ]['recipient'] = $this->find_recipient($rpt_hash['per_recipient'][ $i ]);
@@ -436,8 +421,7 @@ public function get_the_facts($eml)
}
}
}
- else if (isset($this->head_hash['X-failed-recipients']))
- {
+ else if (isset($this->head_hash['X-failed-recipients'])) {
// Busted Exim MTA
// Up to 50 email addresses can be listed on each header.
// There can be multiple X-Failed-Recipients: headers. - (not supported)
@@ -449,8 +433,7 @@ public function get_the_facts($eml)
$this->output[ $j ]['action'] = $this->get_action_from_status_code($this->output[ $j ]['status']);
}
}
- else if (!empty($boundary) && $this->looks_like_a_bounce)
- {
+ else if (!empty($boundary) && $this->looks_like_a_bounce) {
// oh god it could be anything, but at least it has mime parts, so let's try anyway
$arrFailed = $this->find_email_addresses($mime_sections['first_body_part']);
for ($j = 0; $j < count($arrFailed); $j++)
@@ -460,8 +443,7 @@ public function get_the_facts($eml)
$this->output[ $j ]['action'] = $this->get_action_from_status_code($this->output[ $j ]['status']);
}
}
- else if ($this->looks_like_a_bounce)
- {
+ else if ($this->looks_like_a_bounce) {
// last ditch attempt
// could possibly produce erroneous output, or be very resource consuming,
// so be careful. You should comment out this section if you are very concerned
@@ -481,8 +463,7 @@ public function get_the_facts($eml)
$tmp = array();
foreach ($this->output as $arr)
{
- if (empty($arr['recipient']) && empty($arr['status']) && empty($arr['action']))
- {
+ if (empty($arr['recipient']) && empty($arr['status']) && empty($arr['action'])) {
continue;
}
$tmp[] = $arr;
@@ -500,20 +481,16 @@ public function get_the_facts($eml)
$this->feedback_type = (isset($this->fbl_hash['Feedback-type'])) ? $this->fbl_hash['Feedback-type'] : "";
// sniff out any web beacons
- if ($this->web_beacon_preg_1)
- {
+ if ($this->web_beacon_preg_1) {
$this->web_beacon_1 = $this->find_web_beacon($body, $this->web_beacon_preg_1);
}
- if ($this->web_beacon_preg_2)
- {
+ if ($this->web_beacon_preg_2) {
$this->web_beacon_2 = $this->find_web_beacon($body, $this->web_beacon_preg_2);
}
- if ($this->x_header_search_1)
- {
+ if ($this->x_header_search_1) {
$this->x_header_beacon_1 = $this->find_x_header($this->x_header_search_1);
}
- if ($this->x_header_search_2)
- {
+ if ($this->x_header_search_2) {
$this->x_header_beacon_2 = $this->find_x_header($this->x_header_search_2);
}
@@ -532,9 +509,9 @@ function init_bouncehandler($blob, $format = 'string')
$this->head_hash = array();
$this->fbl_hash = array();
$this->body_hash = array();
- $this->looks_like_a_bounce = FALSE;
- $this->looks_like_an_FBL = FALSE;
- $this->is_hotmail_fbl = FALSE;
+ $this->looks_like_a_bounce = false;
+ $this->looks_like_an_FBL = false;
+ $this->is_hotmail_fbl = false;
$this->type = "";
$this->feedback_type = "";
$this->action = "";
@@ -564,9 +541,9 @@ function init_bouncehandler($blob, $format = 'string')
$strEmail = str_replace("\r\n", "\n", $blob); // line returns 1
$strEmail = str_replace("\n", "\r\n", $strEmail);// line returns 2
- # $strEmail = str_replace("=\r\n", "", $strEmail); // remove MIME line breaks (would never exist as #1 above would have dealt with)
- # $strEmail = str_replace("=3D", "=", $strEmail); // equals sign - dealt with in the MIME decode section now
- # $strEmail = str_replace("=09", " ", $strEmail); // tabs
+ // $strEmail = str_replace("=\r\n", "", $strEmail); // remove MIME line breaks (would never exist as #1 above would have dealt with)
+ // $strEmail = str_replace("=3D", "=", $strEmail); // equals sign - dealt with in the MIME decode section now
+ // $strEmail = str_replace("=09", " ", $strEmail); // tabs
//}
//else if($format=='array'){
@@ -589,20 +566,17 @@ function init_bouncehandler($blob, $format = 'string')
*/
function parse_head($headers)
{
- if (!is_array($headers))
- {
+ if (!is_array($headers)) {
$headers = explode("\r\n", $headers);
}
$hash = $this->standard_parser($headers);
- if (isset($hash['Content-type']))
- {//preg_match('/Multipart\/Report/i', $hash['Content-type'])){
+ if (isset($hash['Content-type'])) {//preg_match('/Multipart\/Report/i', $hash['Content-type'])){
$multipart_report = explode(';', $hash['Content-type']);
$hash['Content-type'] = '';
$hash['Content-type']['type'] = strtolower($multipart_report[0]);
foreach ($multipart_report as $mr)
{
- if (preg_match('/([^=.]*?)=(.*)/i', $mr, $matches))
- {
+ if (preg_match('/([^=.]*?)=(.*)/i', $mr, $matches)) {
// didn't work when the content-type boundary ID contained an equal sign,
// that exists in bounces from many Exchange servers
//if(preg_match('/([a-z]*)=(.*)?/i', $mr, $matches)){
@@ -622,44 +596,38 @@ function parse_head($headers)
* @return array
*/
function standard_parser($content)
- { // associative array orstr
+ {
+ // associative array orstr
// receives email head as array of lines
// simple parse (Entity: value\n)
$hash = array('Received' => '');
- if (!is_array($content))
- {
+ if (!is_array($content)) {
$content = explode("\r\n", $content);
}
foreach ($content as $line)
{
- if (preg_match('/^([^\s.]*):\s*(.*)\s*/', $line, $array))
- {
+ if (preg_match('/^([^\s.]*):\s*(.*)\s*/', $line, $array)) {
$entity = ucfirst(strtolower($array[1]));
- if (isset($array[2]) && strpos($array[2], '=?') !== FALSE
+ if (isset($array[2]) && strpos($array[2], '=?') !== false
) // decode MIME Header encoding (subject lines etc)
{
$array[2] = iconv_mime_decode($array[2], ICONV_MIME_DECODE_CONTINUE_ON_ERROR, "UTF-8");
}
- if (empty($hash[ $entity ]))
- {
+ if (empty($hash[ $entity ])) {
$hash[ $entity ] = trim($array[2]);
}
- else if ($hash['Received'])
- {
+ else if ($hash['Received']) {
// grab extra Received headers :(
// pile it on with pipe delimiters,
// oh well, SMTP is broken in this way
- if ($entity and $array[2] and $array[2] != $hash[ $entity ])
- {
+ if ($entity and $array[2] and $array[2] != $hash[ $entity ]) {
$hash[ $entity ] .= "|" . trim($array[2]);
}
}
}
- elseif (isset($line) && isset($entity) && preg_match('/^\s+(.+)\s*/', $line) && $entity)
- {
+ elseif (isset($line) && isset($entity) && preg_match('/^\s+(.+)\s*/', $line) && $entity) {
$line = trim($line);
- if (isset($array[2]) && strpos($array[2], '=?') !== FALSE)
- {
+ if (isset($array[2]) && strpos($array[2], '=?') !== false) {
$line = iconv_mime_decode($array[2], ICONV_MIME_DECODE_CONTINUE_ON_ERROR, "UTF-8");
}
$hash[ $entity ] .= ' ' . $line;
@@ -675,25 +643,23 @@ function standard_parser($content)
/**
* Split an email into multiple mime sections
*
- * @param string|array $body Body of the email
- * @param string $boundary The boundary MIME separator.
+ * @param string|array $body Body of the email
+ * @param string $boundary The boundary MIME separator.
*
* @return array
*/
function parse_body_into_mime_sections($body, $boundary)
{
- if (!$boundary)
- {
+ if (!$boundary) {
return array();
}
- if (is_array($body))
- {
+ if (is_array($body)) {
$body = implode("\r\n", $body);
}
$body = explode($boundary, $body);
- $mime_sections['first_body_part'] = isset($body[1]) ? $this->contenttype_decode($body[1]) : ''; #proper MIME decode
+ $mime_sections['first_body_part'] = isset($body[1]) ? $this->contenttype_decode($body[1]) : ''; // proper MIME decode
$mime_sections['machine_parsable_body_part'] = isset($body[2]) ? $this->contenttype_decode($body[2]) : '';
$mime_sections['returned_message_body_part'] = isset($body[3]) ? $this->contenttype_decode($body[3]) : '';
return $mime_sections;
@@ -712,8 +678,7 @@ function contenttype_decode($mimepart)
$decoded = '';
foreach (explode("\r\n", $mimepart) as $line)
{
- if (preg_match("/^Content-Transfer-Encoding:\s*(\S+)/", $line, $match))
- {
+ if (preg_match("/^Content-Transfer-Encoding:\s*(\S+)/", $line, $match)) {
$encoding = $match[1];
$decoded .= $line . "\r\n";
}
@@ -721,25 +686,26 @@ function contenttype_decode($mimepart)
{
switch ($encoding)
{
- case 'quoted-printable':
- if (substr($line, -1) == '=')
- {
- $line = substr($line, 0, -1);
- }
- else
- {
- $line .= "\r\n";
- }
- $decoded .= preg_replace_callback("/=([0-9A-F][0-9A-F])/", function ($matches)
- {
- return chr(hexdec($matches[0]));
- }, $line);
- break;
- case 'base64':
- $decoded .= base64_decode($line);
- break;
- default: # 7bit, 8bit, binary
- $decoded .= $line . "\r\n";
+ case 'quoted-printable':
+ if (substr($line, -1) == '=') {
+ $line = substr($line, 0, -1);
+ }
+ else
+ {
+ $line .= "\r\n";
+ }
+ $decoded .= preg_replace_callback(
+ "/=([0-9A-F][0-9A-F])/", function ($matches)
+ {
+ return chr(hexdec($matches[0]));
+ }, $line
+ );
+ break;
+ case 'base64':
+ $decoded .= base64_decode($line);
+ break;
+ default: // 7bit, 8bit, binary
+ $decoded .= $line . "\r\n";
}
}
}
@@ -756,20 +722,18 @@ function is_a_bounce()
{
foreach ($this->bouncesubj as $s)
{
- if (preg_match("/^$s/i", $this->head_hash['Subject']))
- {
- return TRUE;
+ if (preg_match("/^$s/i", $this->head_hash['Subject'])) {
+ return true;
}
}
- #if(@preg_match('/auto_reply/',$this->head_hash['Precedence'])) return TRUE; # autoresponse, not bounce
- if (isset($this->head_hash['From']) &&
- preg_match("/^(postmaster|mailer-daemon)\@?/i", $this->head_hash['From'])
- )
- {
- return TRUE;
+ // if(@preg_match('/auto_reply/',$this->head_hash['Precedence'])) return TRUE; # autoresponse, not bounce
+ if (isset($this->head_hash['From'])
+ && preg_match("/^(postmaster|mailer-daemon)\@?/i", $this->head_hash['From'])
+ ) {
+ return true;
}
- return FALSE;
+ return false;
}
/**
@@ -779,32 +743,30 @@ function is_a_bounce()
*/
function is_an_ARF()
{
- if (isset($this->head_hash['Content-type']['report-type']) && preg_match('/feedback-report/',
- $this->head_hash['Content-type']['report-type'])
+ if (isset($this->head_hash['Content-type']['report-type']) && preg_match(
+ '/feedback-report/',
+ $this->head_hash['Content-type']['report-type']
)
- {
- return TRUE;
+ ) {
+ return true;
}
- if (isset($this->head_hash['X-loop']) && preg_match('/scomp/', $this->head_hash['X-loop']))
- {
- return TRUE;
+ if (isset($this->head_hash['X-loop']) && preg_match('/scomp/', $this->head_hash['X-loop'])) {
+ return true;
}
- if (isset($this->head_hash['X-hmxmroriginalrecipient']))
- {
- $this->is_hotmail_fbl = TRUE;
+ if (isset($this->head_hash['X-hmxmroriginalrecipient'])) {
+ $this->is_hotmail_fbl = true;
$this->recipient = $this->head_hash['X-hmxmroriginalrecipient'];
- return TRUE;
+ return true;
}
- if (isset($this->first_body_hash['X-hmxmroriginalrecipient']))
- {
- $this->is_hotmail_fbl = TRUE;
+ if (isset($this->first_body_hash['X-hmxmroriginalrecipient'])) {
+ $this->is_hotmail_fbl = true;
$this->recipient = $this->first_body_hash['X-hmxmroriginalrecipient'];
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
/**
@@ -816,35 +778,32 @@ function is_an_autoresponse()
{
foreach (array('Auto-submitted', 'X-autorespond') as $a)
{
- if (isset($this->head_hash[ $a ]))
- {
+ if (isset($this->head_hash[ $a ])) {
$this->autoresponse = "$a: " . $this->head_hash[ $a ];
- return TRUE;
+ return true;
}
}
foreach (array('Precedence', 'X-precedence') as $a)
{
- if (isset($this->head_hash[ $a ]) && preg_match('/^(auto|junk)/i', $this->head_hash[ $a ]))
- {
+ if (isset($this->head_hash[ $a ]) && preg_match('/^(auto|junk)/i', $this->head_hash[ $a ])) {
$this->autoresponse = "$a: " . $this->head_hash[ $a ];
- return TRUE;
+ return true;
}
}
$subj = isset($this->head_hash['Subject']) ? $this->head_hash['Subject'] : '';
foreach ($this->autorespondlist as $a)
{
- if (preg_match("/$a/i", $subj))
- {
+ if (preg_match("/$a/i", $subj)) {
$this->autoresponse = $this->head_hash['Subject'];
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
/**
@@ -856,8 +815,7 @@ function is_an_autoresponse()
*/
private function strip_angle_brackets($recipient)
{
- if (preg_match('/[<[](.*)[>\]]/', $recipient, $matches))
- {
+ if (preg_match('/[<[](.*)[>\]]/', $recipient, $matches)) {
return trim($matches[1]);
}
else
@@ -886,8 +844,7 @@ function find_email_addresses($first_body_part)
$regExp='/(?:[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/iS';
$matched=preg_match($regExp, $first_body_part, $matches);
- if (1===$matched)
- {
+ if (1===$matched) {
return array($matches[0]);
}
else
@@ -899,7 +856,7 @@ function find_email_addresses($first_body_part)
/**
* Is this an RFC 1892 multiple return email?
*
- * @param array $head_hash Associative array of headers. If not set, will use $this->head_hash
+ * @param array $head_hash Associative array of headers. If not set, will use $this->head_hash
* @return bool
*/
public function is_RFC1892_multipart_report($head_hash=array())
@@ -907,16 +864,16 @@ public function is_RFC1892_multipart_report($head_hash=array())
if (empty($head_hash)) {
$head_hash=$this->head_hash;
}
- if (isset($head_hash['Content-type']['type']) &&
- isset($head_hash['Content-type']['report-type']) &&
- isset($head_hash['Content-type']['boundary']) &&
- 'multipart/report'===$head_hash['Content-type']['type'] &&
- 'delivery-status'===$head_hash['Content-type']['report-type'] &&
- ''!==$head_hash['Content-type']['boundary']
+ if (isset($head_hash['Content-type']['type'])
+ && isset($head_hash['Content-type']['report-type'])
+ && isset($head_hash['Content-type']['boundary'])
+ && 'multipart/report'===$head_hash['Content-type']['type']
+ && 'delivery-status'===$head_hash['Content-type']['report-type']
+ && ''!==$head_hash['Content-type']['boundary']
) {
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
/**
@@ -930,23 +887,20 @@ function parse_machine_parsable_body_part($str)
$hash = $this->parse_dsn_fields($str);
$hash['mime_header'] = $this->standard_parser($hash['mime_header']);
$hash['per_message'] = isset($hash['per_message']) ? $this->standard_parser($hash['per_message']) : array();
- if (isset($hash['per_message']['X-postfix-sender']))
- {
+ if (isset($hash['per_message']['X-postfix-sender'])) {
$arr = explode(';', $hash['per_message']['X-postfix-sender']);
$hash['per_message']['X-postfix-sender'] = '';
$hash['per_message']['X-postfix-sender']['type'] = @trim($arr[0]);
$hash['per_message']['X-postfix-sender']['addr'] = @trim($arr[1]);
}
- if (isset($hash['per_message']['Reporting-mta']))
- {
+ if (isset($hash['per_message']['Reporting-mta'])) {
$arr = explode(';', $hash['per_message']['Reporting-mta']);
$hash['per_message']['Reporting-mta'] = '';
$hash['per_message']['Reporting-mta']['type'] = @trim($arr[0]);
$hash['per_message']['Reporting-mta']['addr'] = @trim($arr[1]);
}
//Per-Recipient DSN fields
- if (isset($hash['per_recipient']))
- {
+ if (isset($hash['per_recipient'])) {
for ($i = 0; $i < count($hash['per_recipient']); $i++)
{
$temp = $this->standard_parser(explode("\r\n", $hash['per_recipient'][ $i ]));
@@ -966,10 +920,8 @@ function parse_machine_parsable_body_part($str)
// temporary failure in this case.
$ddc = $this->decode_diagnostic_code($temp['Diagnostic-code']['text']);
$judgement = $this->get_action_from_status_code($ddc);
- if ($judgement == 'transient')
- {
- if (stristr($temp['Action'], 'failed') !== FALSE)
- {
+ if ($judgement == 'transient') {
+ if (stristr($temp['Action'], 'failed') !== false) {
$temp['Action'] = 'transient';
$temp['Status'] = '4.3.0';
}
@@ -991,8 +943,7 @@ function parse_machine_parsable_body_part($str)
*/
function parse_dsn_fields($dsn_fields)
{
- if (!is_array($dsn_fields))
- {
+ if (!is_array($dsn_fields)) {
$dsn_fields = explode("\r\n\r\n", $dsn_fields);
}
$hash = array();
@@ -1001,12 +952,10 @@ function parse_dsn_fields($dsn_fields)
for ($i = 0; $i < count($dsn_fields); $i++)
{
$dsn_fields[ $i ] = trim($dsn_fields[ $i ]);
- if ($i == 0)
- {
+ if ($i == 0) {
$hash['mime_header'] = $dsn_fields[0];
}
- elseif ($i == 1 && !preg_match('/(Final|Original)-Recipient/', $dsn_fields[1]))
- {
+ elseif ($i == 1 && !preg_match('/(Final|Original)-Recipient/', $dsn_fields[1])) {
// some mta's don't output the per_message part, which means
// the second element in the array should really be
// per_recipient - test with Final-Recipient - which should always
@@ -1015,8 +964,7 @@ function parse_dsn_fields($dsn_fields)
}
else
{
- if ($dsn_fields[ $i ] == '--')
- {
+ if ($dsn_fields[ $i ] == '--') {
continue;
}
$hash['per_recipient'][ $j ] = $dsn_fields[ $i ];
@@ -1041,10 +989,8 @@ private function format_final_recipient_array($arr)
'addr' => '',
'type' => ''
);
- if (isset($arr[1]))
- {
- if (strpos($arr[0], '@') !== FALSE)
- {
+ if (isset($arr[1])) {
+ if (strpos($arr[0], '@') !== false) {
$output['addr'] = $this->strip_angle_brackets($arr[0]);
$output['type'] = (!empty($arr[1])) ? trim($arr[1]) : 'unknown';
}
@@ -1054,8 +1000,7 @@ private function format_final_recipient_array($arr)
$output['addr'] = $this->strip_angle_brackets($arr[1]);
}
} elseif (isset($arr[0])) {
- if (strpos($arr[0], '@') !== FALSE)
- {
+ if (strpos($arr[0], '@') !== false) {
$output['addr'] = $this->strip_angle_brackets($arr[0]);
$output['type'] = 'unknown';
}
@@ -1073,12 +1018,10 @@ private function format_final_recipient_array($arr)
*/
function decode_diagnostic_code($dcode)
{
- if (preg_match("/(\d\.\d\.\d)\s/", $dcode, $array))
- {
+ if (preg_match("/(\d\.\d\.\d)\s/", $dcode, $array)) {
return $array[1];
}
- else if (preg_match("/(\d\d\d)\s/", $dcode, $array))
- {
+ else if (preg_match("/(\d\d\d)\s/", $dcode, $array)) {
return $array[1];
}
@@ -1094,8 +1037,7 @@ function decode_diagnostic_code($dcode)
*/
function get_action_from_status_code($code)
{
- if ($code == '')
- {
+ if ($code == '') {
return '';
}
$ret = $this->format_status_code($code);
@@ -1108,19 +1050,19 @@ function get_action_from_status_code($code)
/**
* Work out the rough status from the first digit of the code
*/
- switch (substr($ret['code'],0,1))
+ switch (substr($ret['code'], 0, 1))
{
- case(2):
- return 'success';
+ case(2):
+ return 'success';
break;
- case(4):
- return 'transient';
+ case(4):
+ return 'transient';
break;
- case(5):
- return 'failed';
+ case(5):
+ return 'failed';
break;
- default:
- return '';
+ default:
+ return '';
break;
}
}
@@ -1135,13 +1077,11 @@ function get_action_from_status_code($code)
function format_status_code($code)
{
$ret = array('code'=>'','text'=>'');
- if (preg_match('/([245]\.[01234567]\.\d{1,2})\s*(.*)/', $code, $matches))
- {
+ if (preg_match('/([245]\.[01234567]\.\d{1,2})\s*(.*)/', $code, $matches)) {
$ret['code'] = $matches[1];
$ret['text'] = $matches[2];
}
- else if (preg_match('/([245])([01234567])(\d{1,2})\s*(.*)/', $code, $matches))
- {
+ else if (preg_match('/([245])([01234567])(\d{1,2})\s*(.*)/', $code, $matches)) {
$ret['code'] = $matches[1] . '.' . $matches[2] . '.' . $matches[3];
$ret['text'] = $matches[4];
}
@@ -1159,12 +1099,10 @@ function format_status_code($code)
function find_recipient($per_rcpt)
{
$recipient = '';
- if ($per_rcpt['Original-recipient']['addr'] !== '')
- {
+ if ($per_rcpt['Original-recipient']['addr'] !== '') {
$recipient = $per_rcpt['Original-recipient']['addr'];
}
- else if ($per_rcpt['Final-recipient']['addr'] !== '')
- {
+ else if ($per_rcpt['Final-recipient']['addr'] !== '') {
$recipient = $per_rcpt['Final-recipient']['addr'];
}
$recipient = $this->strip_angle_brackets($recipient);
@@ -1185,19 +1123,16 @@ function get_status_code_from_text($recipient, $index)
$line = trim($this->body_hash[ $i ]);
//skip Message-ID lines
- if (stripos($line, 'Message-ID') !== FALSE)
- {
+ if (stripos($line, 'Message-ID') !== false) {
continue;
}
/******** recurse into the email if you find the recipient ********/
- if (stristr($line, $recipient) !== FALSE)
- {
+ if (stristr($line, $recipient) !== false) {
// the status code MIGHT be in the next few lines after the recipient line,
// depending on the message from the foreign host... What a laugh riot!
$status_code = $this->get_status_code_from_text($recipient, $i + 1);
- if ($status_code)
- {
+ if ($status_code) {
return $status_code;
}
@@ -1205,67 +1140,61 @@ function get_status_code_from_text($recipient, $index)
/******** exit conditions ********/
// if it's the end of the human readable part in this stupid bounce
- if (stristr($line, '------ This is a copy of the message') !== FALSE)
- {
+ if (stristr($line, '------ This is a copy of the message') !== false) {
break;
}
//if we see an email address other than our current recipient's,
if (count($this->find_email_addresses($line)) >= 1
- && stristr($line, $recipient) === FALSE
- && strstr($line, 'FROM:<') === FALSE
- )
- { // Kanon added this line because Hotmail puts the e-mail address too soon and there actually is error message stuff after it.
+ && stristr($line, $recipient) === false
+ && strstr($line, 'FROM:<') === false
+ ) { // Kanon added this line because Hotmail puts the e-mail address too soon and there actually is error message stuff after it.
break;
}
//******** pattern matching ********/
foreach ($this->bouncelist as $bouncetext => $bouncecode)
{
- if (preg_match("/$bouncetext/i", $line, $matches))
- {
+ if (preg_match("/$bouncetext/i", $line, $matches)) {
return (isset($matches[1])) ? $matches[1] : $bouncecode;
}
}
// Search for a rfc3463 style return code
- if (preg_match('/\W([245]\.[01234567]\.[0-9]{1,2})\W/', $line, $matches))
- {
+ if (preg_match('/\W([245]\.[01234567]\.[0-9]{1,2})\W/', $line, $matches)) {
return $matches[1];
- #??? this seems somewhat redundant
- # $mycode = str_replace('.', '', $matches[1]);
- # $mycode = $this->format_status_code($mycode);
- # return implode('.', $mycode['code']); #x.y.z format
+ // ??? this seems somewhat redundant
+ // $mycode = str_replace('.', '', $matches[1]);
+ // $mycode = $this->format_status_code($mycode);
+ // return implode('.', $mycode['code']); #x.y.z format
}
// search for RFC2821 return code
// thanks to mark.tolman@gmail.com
// Maybe at some point it should have it's own place within the main parsing scheme (at line 88)
- if (preg_match('/\]?: ([45][01257][012345]) /', $line, $matches) ||
- preg_match('/^([45][01257][012345]) (?:.*?)(?:denied|inactive|deactivated|rejected|disabled|unknown|no such|not (?:our|activated|a valid))+/i',
- $line, $matches)
- )
- {
+ if (preg_match('/\]?: ([45][01257][012345]) /', $line, $matches)
+ || preg_match(
+ '/^([45][01257][012345]) (?:.*?)(?:denied|inactive|deactivated|rejected|disabled|unknown|no such|not (?:our|activated|a valid))+/i',
+ $line, $matches
+ )
+ ) {
$mycode = $matches[1];
// map RFC2821 -> RFC3463 codes
- if ($mycode == '550' || $mycode == '551' || $mycode == '553' || $mycode == '554')
- {
+ if ($mycode == '550' || $mycode == '551' || $mycode == '553' || $mycode == '554') {
return '5.1.1';
- } #perm error
- elseif ($mycode == '452' || $mycode == '552')
- {
+ } // perm error
+ elseif ($mycode == '452' || $mycode == '552') {
return '4.2.2';
- } #mailbox full
- elseif ($mycode == '450' || $mycode == '421')
- {
+ } // mailbox full
+ elseif ($mycode == '450' || $mycode == '421') {
return '4.3.2';
- } #temp unavailable
- #???$mycode = $this->format_status_code($mycode);
- #???return implode('.', $mycode['code']);
+ } // temp unavailable
+ // ???$mycode = $this->format_status_code($mycode);
+ // ???return implode('.', $mycode['code']);
}
}
- return '5.5.0'; #other or unknown status
+ return '5.5.0'; // other or unknown status
}
@@ -1276,21 +1205,18 @@ function get_status_code_from_text($recipient, $index)
*/
function find_type()
{
- if ($this->looks_like_a_bounce)
- {
+ if ($this->looks_like_a_bounce) {
return "bounce";
}
- elseif ($this->looks_like_an_FBL)
- {
+ elseif ($this->looks_like_an_FBL) {
return "fbl";
}
- elseif ($this->looks_like_an_autoresponse)
- {
+ elseif ($this->looks_like_an_autoresponse) {
return "autoresponse";
}
else
{
- return FALSE;
+ return false;
}
}
@@ -1306,12 +1232,10 @@ function find_type()
*/
public function find_web_beacon($body, $preg)
{
- if (!isset($preg) || !$preg)
- {
+ if (!isset($preg) || !$preg) {
return '';
}
- if (preg_match($preg, $body, $matches))
- {
+ if (preg_match($preg, $body, $matches)) {
return $matches[1];
}
@@ -1330,14 +1254,12 @@ public function find_x_header($xheader)
{
$xheader = ucfirst(strtolower($xheader));
// check the header
- if (isset($this->head_hash[ $xheader ]))
- {
+ if (isset($this->head_hash[ $xheader ])) {
return $this->head_hash[ $xheader ];
}
// check the body too
$tmp_body_hash = $this->standard_parser($this->body_hash);
- if (isset($tmp_body_hash[ $xheader ]))
- {
+ if (isset($tmp_body_hash[ $xheader ])) {
return $tmp_body_hash[ $xheader ];
}
@@ -1370,8 +1292,7 @@ function extract_address($str)
$from_stuff = preg_split('/[ \"\'\<\>:\(\)\[\]]/', $str);
foreach ($from_stuff as $things)
{
- if (strpos($things, '@') !== FALSE)
- {
+ if (strpos($things, '@') !== false) {
$from = $things;
}
}
@@ -1382,9 +1303,9 @@ function extract_address($str)
/**
* Format a status code into a HTML marked up reason.
*
- * @param string $code A status code line.
- * @param array $status_code_classes The rough description of the status code.
- * @param array $status_code_subclasses The details of each specific subcode.
+ * @param string $code A status code line.
+ * @param array $status_code_classes The rough description of the status code.
+ * @param array $status_code_subclasses The details of each specific subcode.
*
* @return string HTML marked up reason
*/
@@ -1396,7 +1317,7 @@ function fetch_status_messages($code,$status_code_classes=array(),$status_code_s
* Load from the provided bounce_statuscodes.php file if not set
*/
if (empty($code_classes) || empty($sub_classes)) {
- include_once("bounce_statuscodes.php");
+ include_once"bounce_statuscodes.php";
if (empty($code_classes)) {
$code_classes=$status_code_classes;
}
@@ -1416,4 +1337,6 @@ function fetch_status_messages($code,$status_code_classes=array(),$status_code_s
}
-/** END class BounceHandler **/
\ No newline at end of file
+/**
+ * END class BounceHandler
+**/
\ No newline at end of file
diff --git a/bounce_responses.php b/bounce_responses.php
index 8967072..09aeac4 100644
--- a/bounce_responses.php
+++ b/bounce_responses.php
@@ -1,422 +1,422 @@
'x',
- # use the code from the regex
+ // use the code from the regex
'Diagnostic[- ][Cc]ode: smtp; ?\d\d\ ([45]\.\d\.\d{1,2})' => 'x',
- # use the code from the regex
+ // use the code from the regex
'Status: ([45]\.\d\.\d{1,2})' => 'x',
- # use the code from the regex
+ // use the code from the regex
'not yet been delivered' => '4.2.0',
- #
+ //
'Message will be retried for' => '4.2.0',
- #
+ //
'Connection frequency limited\. http:\/\/service\.mail\.qq\.com' => '4.2.0',
'Benutzer hat zuviele Mails auf dem Server' => '4.2.2',
- #.DE "mailbox full"
+ // .DE "mailbox full"
'exceeded storage allocation' => '4.2.2',
- #
+ //
'Mailbox full' => '4.2.2',
- #
+ //
'mailbox is full' => '4.2.2',
- #BH
+ // BH
'Mailbox quota usage exceeded' => '4.2.2',
- #BH
+ // BH
'Mailbox size limit exceeded' => '4.2.2',
- #
+ //
'over ?quota' => '4.2.2',
- #
+ //
'quota exceeded' => '4.2.2',
- #
+ //
'Quota violation' => '4.2.2',
- #
+ //
'User has exhausted allowed storage space' => '4.2.2',
- #
+ //
'User has too many messages on the server' => '4.2.2',
- #
+ //
'User mailbox exceeds allowed size' => '4.2.2',
- #
+ //
'mailfolder is full' => '4.2.2',
- #
+ //
'user has Exceeded' => '4.2.2',
- #
+ //
'not enough storage space' => '4.2.2',
- #
+ //
'Delivery attempts will continue to be made for' => '4.3.2',
- #SB: 4.3.2 is a more generic 'defer'; Kanon added. From Symantec_AntiVirus_for_SMTP_Gateways@uqam.ca Im not sure why Symantec delayed this message, but x.2.x means something to do with the mailbox, which seemed appropriate. x.5.x (protocol) or x.7.x (security) also seem possibly appropriate. It seems a lot of times its x.5.x when it seems to me it should be x.7.x, so maybe x.5.x is standard when mail is rejected due to spam-like characteristics instead of x.7.x like I think it should be.
+ // SB: 4.3.2 is a more generic 'defer'; Kanon added. From Symantec_AntiVirus_for_SMTP_Gateways@uqam.ca Im not sure why Symantec delayed this message, but x.2.x means something to do with the mailbox, which seemed appropriate. x.5.x (protocol) or x.7.x (security) also seem possibly appropriate. It seems a lot of times its x.5.x when it seems to me it should be x.7.x, so maybe x.5.x is standard when mail is rejected due to spam-like characteristics instead of x.7.x like I think it should be.
'delivery temporarily suspended' => '4.3.2',
- #
+ //
'Greylisted for 5 minutes' => '4.3.2',
- #
+ //
'Greylisting in action' => '4.3.2',
- #
+ //
'Server busy' => '4.3.2',
- #
+ //
'server too busy' => '4.3.2',
- #
+ //
'system load is too high' => '4.3.2',
- #
+ //
'temporarily deferred' => '4.3.2',
- #
+ //
'temporarily unavailable' => '4.3.2',
- #
+ //
'Throttling' => '4.3.2',
- #
+ //
'too busy to accept mail' => '4.3.2',
- #
+ //
'too many connections' => '4.3.2',
- #
+ //
'too many sessions' => '4.3.2',
- #
+ //
'Too much load' => '4.3.2',
- #
+ //
'try again later' => '4.3.2',
- #
+ //
'Try later' => '4.3.2',
- #
+ //
'retry timeout exceeded' => '4.4.7',
- #
+ //
'queue too long' => '4.4.7',
- #
+ //
'554 delivery error:' => '5.1.1',
- #SB: Yahoo/rogers.com generic delivery failure (see also OU-00)
+ // SB: Yahoo/rogers.com generic delivery failure (see also OU-00)
'account has been disabled' => '5.1.1',
- #
+ //
'account is unavailable' => '5.1.1',
- #
+ //
'Account not found' => '5.1.1',
- #
+ //
'Address invalid' => '5.1.1',
- #
+ //
'Address is unknown' => '5.1.1',
- #
+ //
'Address unknown' => '5.1.1',
- #
+ //
'Addressee unknown' => '5.1.1',
- #
+ //
'ADDRESS_NOT_FOUND' => '5.1.1',
- #
+ //
'bad address' => '5.1.1',
- #
+ //
'Bad destination mailbox address' => '5.1.1',
- #
+ //
'destin. Sconosciuto' => '5.1.1',
- #.IT "user unknown"
+ // .IT "user unknown"
'Destinatario errato' => '5.1.1',
- #.IT "invalid"
+ // .IT "invalid"
'Destinatario sconosciuto o mailbox disatttivata' => '5.1.1',
- #.IT "unknown /disabled"
+ // .IT "unknown /disabled"
'does not exist' => '5.1.1',
- #
+ //
'Email Address was not found' => '5.1.1',
- #
+ //
'Excessive userid unknowns' => '5.1.1',
- #
+ //
'Indirizzo inesistente' => '5.1.1',
- #.IT "no user"
+ // .IT "no user"
'Invalid account' => '5.1.1',
- #
+ //
'invalid address' => '5.1.1',
- #
+ //
'Invalid or unknown virtual user' => '5.1.1',
- #
+ //
'Invalid mailbox' => '5.1.1',
- #
+ //
'Invalid recipient' => '5.1.1',
- #
+ //
'Mailbox not found' => '5.1.1',
- #
+ //
'mailbox unavailable' => '5.1.1',
- #
+ //
'nie istnieje' => '5.1.1',
- #.PL "does not exist"
+ // .PL "does not exist"
'Nie ma takiego konta' => '5.1.1',
- #.PL "no such account"
+ // .PL "no such account"
'No mail box available for this user' => '5.1.1',
- #
+ //
'no mailbox here' => '5.1.1',
- #
+ //
'No one with that email address here' => '5.1.1',
- #
+ //
'no such address' => '5.1.1',
- #
+ //
'no such email address' => '5.1.1',
- #
+ //
'No such mail drop defined' => '5.1.1',
- #
+ //
'No such mailbox' => '5.1.1',
- #
+ //
'No such person at this address' => '5.1.1',
- #
+ //
'no such recipient' => '5.1.1',
- #
+ //
'No such user' => '5.1.1',
- #
+ //
'not a known user' => '5.1.1',
- #
+ //
'not a valid mailbox' => '5.1.1',
- #
+ //
'not a valid user' => '5.1.1',
- #
+ //
'not available' => '5.1.1',
- #
+ //
'not exists' => '5.1.1',
- #
+ //
'Recipient address rejected' => '5.1.1',
- #
+ //
'Recipient not allowed' => '5.1.1',
- #
+ //
'Recipient not found' => '5.1.1',
- #
+ //
'recipient rejected' => '5.1.1',
- #
+ //
'Recipient unknown' => '5.1.1',
- #
+ //
"server doesn't handle mail for that user" => '5.1.1',
- #
+ //
'This account is disabled' => '5.1.1',
- #
+ //
'This address no longer accepts mail' => '5.1.1',
- #
+ //
'This email address is not known to this system' => '5.1.1',
- #
+ //
'Unknown account' => '5.1.1',
- #
+ //
'unknown address or alias' => '5.1.1',
- #
+ //
'Unknown email address' => '5.1.1',
- #
+ //
'Unknown local part' => '5.1.1',
- #
+ //
'unknown or illegal alias' => '5.1.1',
- #
+ //
'unknown or illegal user' => '5.1.1',
- #
+ //
'Unknown recipient' => '5.1.1',
- #
+ //
'unknown user' => '5.1.1',
- #
+ //
'user disabled' => '5.1.1',
- #
+ //
"User doesn't exist in this server" => '5.1.1',
- #
+ //
'user invalid' => '5.1.1',
- #
+ //
'User is suspended' => '5.1.1',
- #
+ //
'User is unknown' => '5.1.1',
- #
+ //
'User not found' => '5.1.1',
- #
+ //
'User not known' => '5.1.1',
- #
+ //
'User unknown' => '5.1.1',
- #
+ //
'valid RCPT command must precede DATA' => '5.1.1',
- #
+ //
'was not found in LDAP server' => '5.1.1',
- #
+ //
'We are sorry but the address is invalid' => '5.1.1',
- #
+ //
'Unable to find alias user' => '5.1.1',
- #
+ //
"domain isn't in my list of allowed rcpthosts" => '5.1.2',
- #
+ //
'Esta casilla ha expirado por falta de uso' => '5.1.2',
- #BH ES:expired
+ // BH ES:expired
'host ?name is unknown' => '5.1.2',
- #
+ //
'no relaying allowed' => '5.1.2',
- #
+ //
'no such domain' => '5.1.2',
- #
+ //
'not our customer' => '5.1.2',
- #
+ //
'relay not permitted' => '5.1.2',
- #
+ //
'Relay access denied' => '5.1.2',
- #
+ //
'relaying denied' => '5.1.2',
- #
+ //
'Relaying not allowed' => '5.1.2',
- #
+ //
'This system is not configured to relay mail' => '5.1.2',
- #
+ //
'Unable to relay' => '5.1.2',
- #
+ //
'unrouteable mail domain' => '5.1.2',
- #BH
+ // BH
'we do not relay' => '5.1.2',
- #
+ //
'Old address no longer valid' => '5.1.6',
- #
+ //
'recipient no longer on server' => '5.1.6',
- #
+ //
'Sender address rejected' => '5.1.8',
- #
+ //
'exceeded the rate limit' => '5.2.0',
- #
+ //
'Local Policy Violation' => '5.2.0',
- #
+ //
'Mailbox currently suspended' => '5.2.0',
- #
+ //
'mailbox unavailable' => '5.2.0',
- #
+ //
'mail can not be delivered' => '5.2.0',
- #
+ //
'Delivery failed' => '5.2.0',
- #
+ //
'mail couldn\'t be delivered' => '5.2.0',
- #
+ //
'The account or domain may not exist' => '5.2.0',
- #I guess.... seems like 5.1.1, 5.1.2, or 5.4.4 would fit too, but 5.2.0 seemed most generic
+ // I guess.... seems like 5.1.1, 5.1.2, or 5.4.4 would fit too, but 5.2.0 seemed most generic
'Account disabled' => '5.2.1',
- #
+ //
'account has been disabled' => '5.2.1',
- #
+ //
'Account Inactive' => '5.2.1',
- #
+ //
'Adressat unbekannt oder Mailbox deaktiviert' => '5.2.1',
- #
+ //
'Destinataire inconnu ou boite aux lettres desactivee' => '5.2.1',
- #.FR disabled
+ // .FR disabled
'mail is not currently being accepted for this mailbox' => '5.2.1',
- #
+ //
'El usuario esta en estado: inactivo' => '5.2.1',
- #.IT inactive
+ // .IT inactive
'email account that you tried to reach is disabled' => '5.2.1',
- #
+ //
'inactive user' => '5.2.1',
- #
+ //
'Mailbox disabled for this recipient' => '5.2.1',
- #
+ //
'mailbox has been blocked due to inactivity' => '5.2.1',
- #
+ //
'mailbox is currently unavailable' => '5.2.1',
- #
+ //
'Mailbox is disabled' => '5.2.1',
- #
+ //
'Mailbox is inactive' => '5.2.1',
- #
+ //
'Mailbox Locked or Suspended' => '5.2.1',
- #
+ //
'mailbox temporarily disabled' => '5.2.1',
- #
+ //
'Podane konto jest zablokowane administracyjnie lub nieaktywne' => '5.2.1',
- #.PL locked or inactive
+ // .PL locked or inactive
"Questo indirizzo e' bloccato per inutilizzo" => '5.2.1',
- #.IT blocked/expired
+ // .IT blocked/expired
'Recipient mailbox was disabled' => '5.2.1',
- #
+ //
'Domain name not found' => '5.2.1',
'couldn\'t find any host named' => '5.4.4',
- #
+ //
'couldn\'t find any host by that name' => '5.4.4',
- #
+ //
'PERM_FAILURE: DNS Error' => '5.4.4',
- #SB: Routing failure
+ // SB: Routing failure
'Temporary lookup failure' => '5.4.4',
- #
+ //
'unrouteable address' => '5.4.4',
- #
+ //
"can't connect to" => '5.4.4',
- #
+ //
'Too many hops' => '5.4.6',
- #
+ //
'Requested action aborted' => '5.5.0',
- #
+ //
'rejecting password protected file attachment' => '5.6.2',
- #RFC "Conversion required and prohibited"
+ // RFC "Conversion required and prohibited"
'550 OU-00' => '5.7.1',
- #SB hotmail returns a OU-001 if you're on their blocklist
+ // SB hotmail returns a OU-001 if you're on their blocklist
'550 SC-00' => '5.7.1',
- #SB hotmail returns a SC-00x if you're on their blocklist
+ // SB hotmail returns a SC-00x if you're on their blocklist
'550 DY-00' => '5.7.1',
- #SB hotmail returns a DY-00x if you're a dynamic IP
+ // SB hotmail returns a DY-00x if you're a dynamic IP
'554 denied' => '5.7.1',
- #
+ //
'You have been blocked by the recipient' => '5.7.1',
- #
+ //
'requires that you verify' => '5.7.1',
- #
+ //
'Access denied' => '5.7.1',
- #
+ //
'Administrative prohibition - unable to validate recipient' => '5.7.1',
- #
+ //
'Blacklisted' => '5.7.1',
- #
+ //
'blocke?d? for spam' => '5.7.1',
- #
+ //
'conection refused' => '5.7.1',
- #
+ //
'Connection refused due to abuse' => '5.7.1',
- #
+ //
'dial-up or dynamic-ip denied' => '5.7.1',
- #
+ //
'Domain has received too many bounces' => '5.7.1',
- #
+ //
'failed several antispam checks' => '5.7.1',
- #
+ //
'found in a DNS blacklist' => '5.7.1',
- #
+ //
'IPs blocked' => '5.7.1',
- #
+ //
'is blocked by' => '5.7.1',
- #
+ //
'Mail Refused' => '5.7.1',
- #
+ //
'Message does not pass DomainKeys' => '5.7.1',
- #
+ //
'Message looks like spam' => '5.7.1',
- #
+ //
'Message refused by' => '5.7.1',
- #
+ //
'not allowed access from your location' => '5.7.1',
- #
+ //
'permanently deferred' => '5.7.1',
- #
+ //
'Rejected by policy' => '5.7.1',
- #
+ //
'rejected by Windows Live Hotmail for policy reasons' => '5.7.1',
- #
+ //
'Rejected for policy reasons' => '5.7.1',
- #
+ //
'Rejecting banned content' => '5.7.1',
- #
+ //
'Sorry, looks like spam' => '5.7.1',
- #
+ //
'spam message discarded' => '5.7.1',
- #
+ //
'Too many spams from your IP' => '5.7.1',
- #
+ //
'TRANSACTION FAILED' => '5.7.1',
- #
+ //
'Transaction rejected' => '5.7.1',
- #
+ //
'Wiadomosc zostala odrzucona przez system antyspamowy' => '5.7.1',
- #.PL rejected as spam
+ // .PL rejected as spam
'Your message was declared Spam' => '5.7.1'
- #
+ //
);
-# triggers for autoresponders
+// triggers for autoresponders
$autorespondlist = array(
'^\[?auto.{0,20}reply\]?',
'^auto[ -]?response',
@@ -425,10 +425,10 @@
'^Vacation.{0,20}(reply|respon)',
'^out.?of (the )?office',
'^(I am|I\'m).{0,20}\s(away|on vacation|on leave|out of office|out of the office)',
- "\350\207\252\345\212\250\345\233\236\345\244\215" #sino.com, 163.com UTF8 encoded
+ "\350\207\252\345\212\250\345\233\236\345\244\215" // sino.com, 163.com UTF8 encoded
);
-# trigger subject lines for bounces
+// trigger subject lines for bounces
$bouncesubj = array(
'deletver reports about your e?mail',
'delivery errors',
@@ -440,7 +440,7 @@
'delivery status notif',
'failure delivery',
'failure notice',
- 'mail delivery fail', #catches failure and failed
+ 'mail delivery fail', // catches failure and failed
'mail delivery system',
'mailserver notification',
'mail status report',
@@ -449,9 +449,9 @@
'mdaemon notification',
'message delayed',
'nondeliverable mail',
- 'Non[_ ]remis[_ ]', #fr
- 'No[_ ]se[_ ]puede[_ ]entregar', #es
- 'Onbestelbaar', #nl
+ 'Non[_ ]remis[_ ]', // fr
+ 'No[_ ]se[_ ]puede[_ ]entregar', // es
+ 'Onbestelbaar', // nl
'returned e?mail',
'returned to sender',
'returning message to sender',
@@ -461,13 +461,13 @@
'warning: message',
);
-#
-# test mapping to ensure that we don't match one within another
-#
-#foreach ($bouncelist as $l1 => $j) {
-# foreach ($bouncelist as $l2 => $k) {
-# if (($l1 != $l2) && preg_match("/$l1/i", $l2)) {
-# print "'$l1'($j) = '$l2'($k)\n";
-# }
-# }
-#}
\ No newline at end of file
+//
+// test mapping to ensure that we don't match one within another
+//
+// foreach ($bouncelist as $l1 => $j) {
+// foreach ($bouncelist as $l2 => $k) {
+// if (($l1 != $l2) && preg_match("/$l1/i", $l2)) {
+// print "'$l1'($j) = '$l2'($k)\n";
+// }
+// }
+// }
\ No newline at end of file
diff --git a/bounce_statuscodes.php b/bounce_statuscodes.php
index 4eed64d..c7ad3e7 100644
--- a/bounce_statuscodes.php
+++ b/bounce_statuscodes.php
@@ -1,151 +1,151 @@
get_the_facts($email);
- # var_dump($bounceinfo);
- # var_dump($bh);
+ // var_dump($bounceinfo);
+ // var_dump($bh);
print "TYPE " . @$bh->type . "\n";
if ($bh->type == 'bounce') {
print "ACTION " . $bounceinfo[0]['action'] . "\n";
diff --git a/php.bouncehandler.v7.4.zip b/php.bouncehandler.v7.4.zip
deleted file mode 100644
index 9417828cb24dea4f790f6115629cdcd81687fa87..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 317542
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