/** * Check an email. * * @param string $email Contents of an email to check * * @return void */ function checkmail($email) { global $total; $bh = new Bouncehandler(); $bounceinfo = $bh->get_the_facts($email); // var_dump($bounceinfo); // var_dump($bh); print " TYPE " . @$bh->type . "\n"; if ($bh->type == 'bounce') { print " ACTION " . $bounceinfo[0]['action'] . "\n"; print " STATUS " . $bounceinfo[0]['status'] . "\n"; print " RECIPIENT " . $bounceinfo[0]['recipient'] . "\n"; } if ($bh->type == 'fbl') { print " ENV FROM " . @$bh->fbl_hash['Original-mail-from'] . "\n"; print " AGENT " . @$bh->fbl_hash['User-agent'] . "\n"; print " IP " . @$bh->fbl_hash['Source-ip'] . "\n"; } if ($bh->type == 'autoresponse') { print " AUTO " . $bounceinfo[0]['autoresponse'] . "\n"; } if ($bh->type) { @$total[$bh->type]++; } else { @$total['unknown']++; } print "\n"; }
function process($source = '') { global $_E107, $pref; e107::getCache()->CachePageMD5 = '_'; e107::getCache()->set('emailLastBounce', time(), TRUE, FALSE, TRUE); $strEmail = !$source ? $this->mailRead(-1) : file_get_contents(e_HANDLER . "eml/" . $source); if (!$strEmail) { return; } $multiArray = Bouncehandler::get_the_facts($strEmail); $head = BounceHandler::parse_head($strEmail); $e107_userid = isset($head['X-e107-id']) ? intval($head['X-e107-id']) : $this->getHeader($strEmail, 'X-e107-id'); if ($_E107['debug']) { require_once e_HANDLER . "mail.php"; $message = "Your Bounce Handler is working. The data of the email you sent is displayed below.<br />"; if ($e107_userid) { $message .= "A user-id was detected in the email you sent: <b>" . $e107_userid . "</b><br />"; } $message .= "<br />"; $message .= "<pre>" . print_r($multiArray, TRUE) . "</pre>"; $message .= "<pre>" . $strEmail . "</pre>"; sendemail($pref['siteadminemail'], SITENAME . " :: Bounce-Handler.", $message, $pref['siteadmin'], $pref['siteadminemail'], $pref['siteadmin']); } if ($e107_userid && $this->setUser_Bounced($e107_userid) == TRUE) { return; } /* echo "<pre>"; print_r($multiArray); echo "</pre>"; */ foreach ($multiArray as $the) { $the['user_id'] = $head['X-e107-id']; $the['user_email'] = $the['recipient']; unset($the['recipient']); switch ($the['action']) { case 'failed': e107::getEvent()->trigger('email-bounce-failed', $the); $this->setUser_Bounced($the['user_email']); break; case 'transient': // $num_attempts = delivery_attempts($the['user_email']); e107::getEvent()->trigger('email-bounce-transient', $the); if ($num_attempts > 10) { $this->setUser_Bounced($the['user_email'], $the['user_id']); } else { // insert_into_queue($the['user_email'], ($num_attempts+1)); } break; case 'autoreply': e107::getEvent()->trigger('email-bounce-autoreply', $the); // postpone($the['user_email'], '7 days'); break; default: //don't do anything break; } } }
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <body> <?php require_once "bounce_driver.class.php"; $bouncehandler = new Bouncehandler(); if ($_GET['testall']) { $files = get_sorted_file_list('eml'); if (is_array($files)) { echo "<P>File Tests:</P>\n"; foreach ($files as $file) { echo "<a href=\"" . $_SERVER['PHP_SELF'] . "?eml=" . urlencode($file) . "\">{$file}</a> "; $bounce = file_get_contents("eml/" . $file); $multiArray = $bouncehandler->get_the_facts($bounce); if (!empty($multiArray[0]['action']) && !empty($multiArray[0]['status']) && !empty($multiArray[0]['recipient'])) { print " - Passed<br>\n"; } else { print "<font color=red> - WRONG</font><br>\n"; print "<pre>\n"; print_r($multiArray[0]); print "</pre>\n"; } } } } ?> <h1>bounce_driver.class.php -- Version 7.0</h1> <P>
/** * Tests a single email. * * @param string $bounce Contents of the bounce email. * * @return void */ private function _testSingle($bounce) { $multiArray = $this->_bouncehandler->get_the_facts($bounce); echo "<TEXTAREA COLS=100 ROWS=" . count($multiArray) * 8 . ">"; print_r($multiArray); echo "</TEXTAREA>"; $bounce = $this->_bouncehandler->init_bouncehandler($bounce, 'string'); list($head, $body) = preg_split("/\r\n\r\n/", $bounce, 2); echo '<h2>Raw email:</h2><br />'; echo "<TEXTAREA COLS=100 ROWS=12>"; echo htmlspecialchars($bounce); echo "</TEXTAREA><br />"; echo "<h2>Parsed head</h2>\n"; $head_hash = $this->_bouncehandler->parse_head($head); echo "<TEXTAREA COLS=100 ROWS=" . count($head_hash) * 2.7 . ">"; print_r($head_hash); echo "</TEXTAREA><br />"; if ($this->_bouncehandler->is_RFC1892_multipart_report($head_hash)) { echo '<h2 style="color:red;">'; echo 'Looks like an RFC1892 multipart report'; echo '</h2>'; } else { if ($this->_bouncehandler->looks_like_an_FBL) { echo '<h2 style="color:red;">'; echo 'Looks like a feedback loop'; if ($this->_bouncehandler->is_hotmail_fbl) { echo ' in Hotmail Doofus Format (HDF?)'; } else { echo ' in Abuse Feedback Reporting format (ARF)'; } echo '</h2>'; echo "<TEXTAREA COLS=100 ROWS=12>"; print_r($this->_bouncehandler->fbl_hash); echo "</TEXTAREA>"; } else { echo "<h2 style='color:red;'>Not an RFC1892 multipart report</H2>"; echo "<TEXTAREA COLS=100 ROWS=100>"; print_r($body); echo "</TEXTAREA>"; exit; } } echo "<h2>Here is the parsed report</h2>\n"; echo '<p>Postfix adds an appropriate X- header (X-Postfix-Sender:), '; echo 'so you do not need to create one via phpmailer. RFC\'s call '; echo 'for an optional Original-recipient field, but mandatory '; echo 'Final-recipient field is a fair substitute.</p>'; $boundary = $head_hash['Content-type']['boundary']; $mime_sections = $this->_bouncehandler->parse_body_into_mime_sections($body, $boundary); $rpt_hash = $this->_bouncehandler->parse_machine_parsable_body_part($mime_sections['machine_parsable_body_part']); echo "<TEXTAREA COLS=100 ROWS=" . count($rpt_hash) * 16 . ">"; print_r($rpt_hash); echo "</TEXTAREA>"; echo "<h2>Here is the error status code</h2>\n"; echo "<P>It's all in the status code, if you can find one.</P>"; for ($i = 0; $i < count($rpt_hash['per_recipient']); $i++) { echo "<P>Report #" . ($i + 1) . "<BR>\n"; echo $this->_bouncehandler->find_recipient($rpt_hash['per_recipient'][$i]); $scode = $rpt_hash['per_recipient'][$i]['Status']; echo "<PRE>{$scode}</PRE>"; echo $this->_bouncehandler->fetch_status_messages($scode); echo "</P>\n"; } echo '<h2>The Diagnostic-code</h2>'; echo '<p>is not the same as the reported status code, but it seems '; echo 'to be more descriptive, so it should be extracted (if possible).'; for ($i = 0; $i < count($rpt_hash['per_recipient']); $i++) { echo "<P>Report #" . ($i + 1) . " <BR>\n"; echo $this->_bouncehandler->find_recipient($rpt_hash['per_recipient'][$i]); $dcode = $rpt_hash['per_recipient'][$i]['Diagnostic-code']['text']; if ($dcode) { echo "<PRE>{$dcode}</PRE>"; echo $this->_bouncehandler->fetch_status_messages($dcode); } else { echo "<PRE>couldn't decode</PRE>"; } echo "</P>\n"; } echo '<h2>Grab original To: and From:</h2>\\n'; echo '<p>Just in case we don\'t have an Original-recipient: field, or '; echo 'a X-Postfix-Sender: field, we can retrieve information from '; echo 'the (optional) returned message body part</p>' . PHP_EOL; $head = $this->_bouncehandler->get_head_from_returned_message_body_part($mime_sections); echo "<P>From: " . $head['From']; echo "<br>To: " . $head['To']; echo "<br>Subject: " . $head['Subject'] . "</P>"; echo "<h2>Here is the body in RFC1892 parts</h2>\n"; echo '<[>Three parts: [first_body_part], '; echo '[machine_parsable_body_part], and '; echo ' [returned_message_body_part]</p>'; echo "<TEXTAREA cols=100 rows=100>"; print_r($mime_sections); echo "</TEXTAREA>"; }
$password = "******"; $bouncehandler = new Bouncehandler(); $pop3 = new ezcMailPop3Transport($server); $pop3->authenticate($username, $password); $pop3->status($num, $size); $cli->output('Bounce messages to check: ' . $num); $messages = $pop3->listMessages(); foreach ($messages as $index => $size) { $set = $pop3->fetchByMessageNr($index); do { $raw_message = ""; $line = ""; while (($line = $set->getNextLine()) !== null) { $raw_message .= $line; } $result = $bouncehandler->get_the_facts($raw_message); $result = $result[0]; $status = $result['status']; $action = $result['action']; $recipient = trim($result['recipient']); if (!in_array($action, array("delayed", "failed", "autoreply"))) { $cli->output("Message index: {$index}, unknown action: {$action}, skipping..."); continue; } if ($action == 'delayed' || $action == 'autoreply') { $cli->output("Deleting message: {$index}, action: {$action}"); $pop3->delete($index); continue; } if ($action == 'failed') { $cli->output("Message index: {$index}, status: {$status}, action: {$action}, recipient: {$recipient}");
function alo_em_handle_bounces($report = false) { global $wpdb; $output = ''; $bounce_settings = alo_em_bounce_settings(); $conn = alo_em_bounce_connect(); if (!$conn) { return FALSE; } $num_msgs = imap_num_msg($conn); // start bounce class require_once 'inc/bouncehandler/bounce_driver.class.php'; $bouncehandler = new Bouncehandler(); // get the failures $email_addresses = array(); $delete_addresses = array(); $max_msgs = min($num_msgs, $bounce_settings['bounce_maxmsg']); if ($report) { $output .= 'Bounces handled in: ' . $bounce_settings['bounce_email']; } for ($n = 1; $n <= $max_msgs; $n++) { $msg_headers = imap_fetchheader($conn, $n); $msg_body = imap_body($conn, $n); $bounce = $msg_headers . $msg_body; //entire message $multiArray = $bouncehandler->get_the_facts($bounce); if (!empty($multiArray[0]['action']) && !empty($multiArray[0]['status']) && !empty($multiArray[0]['recipient'])) { if ($report) { $output .= '<br /> - MSG #' . $n . ' - Bounce response: ' . $multiArray[0]['action']; } // If delivery permanently failed, unsubscribe if ($multiArray[0]['action'] == 'failed') { $email = trim($multiArray[0]['recipient']); // Unsubscribe email address if ($s_id = alo_em_is_subscriber($email)) { alo_em_delete_subscriber_by_id($s_id); do_action('alo_easymail_bounce_email_unsubscribed', $email); // Hook if ($report) { $output .= ' - ' . $email . ' UNSUBSCRIBED'; } } } // If delivery temporary or permanently failed, mark recipient as bounced if ($multiArray[0]['action'] == 'failed' || $multiArray[0]['action'] == 'transient' || $multiArray[0]['action'] == 'autoreply') { // TODO maybe use: $bouncehandler->x_header_search_1 = 'ALO-EM-Newsletter'; // Look fo EasyMail custom headers: Newsletter and Recipient // NOTE: searching in body because IDs are inside original message included in body $newsletter_id = 0; $recipient_id = 0; if (preg_match('/X-ALO-EM-Newsletter: (\\d+)/i', $bounce, $matches)) { if (!empty($matches[1]) && is_numeric($matches[1])) { $newsletter_id = (int) $matches[1]; } } if (preg_match('/X-ALO-EM-Recipient: (\\d+)/i', $bounce, $matches)) { if (!empty($matches[1]) && is_numeric($matches[1])) { $recipient_id = (int) $matches[1]; } } // Mark recipient as bounced only if not a debug to author if ($newsletter_id > 0 && $recipient_id > 0 && strpos($msg_headers, "( DEBUG - TO: ") === false) { $wpdb->update("{$wpdb->prefix}easymail_recipients", array('result' => -3), array('ID' => $recipient_id, 'newsletter' => $newsletter_id, 'email' => $email)); } if ($report) { $output .= ' - Recipient ID #' . $recipient_id . ' marked as not delivered'; } // mark msg for deletion imap_delete($conn, $n); } } else { if ($report) { $output .= '<br /><span class="description"> - MSG #' . $n . ' - Not a bounce</span>'; } } } //for loop // delete messages imap_expunge($conn); // close imap_close($conn); if ($report) { return $output; } }
function process($source = '') { $pref = e107::getPref(); e107::getCache()->CachePageMD5 = '_'; e107::getCache()->set('emailLastBounce', time(), TRUE, FALSE, TRUE); $strEmail = $this->source == false ? $this->mailRead(-1) : file_get_contents(e_HANDLER . "eml/" . $this->source); file_put_contents(e_LOG . "bounce.log", date('r') . "\n\n" . $strEmail . "\n\n", FILE_APPEND); if (strpos($strEmail, 'X-Bounce-Test: true') !== false) { $this->debug = true; // mode 1 - for email test. } if (empty($strEmail)) { if ($this->debug === true && !empty($this->source)) { echo "Couldn't get email data"; } else { $message = "Empty Email!"; } } else { $multiArray = Bouncehandler::get_the_facts($strEmail); $head = BounceHandler::parse_head($strEmail); $message = null; $identifier = deftrue('MAIL_IDENTIFIER', 'X-e107-id'); $e107_userid = isset($head[$identifier]) ? $head[$identifier] : $this->getHeader($strEmail, $identifier); } if ($this->debug === true) { require_once e_HANDLER . "mail.php"; $message = "Your Bounce Handler is working. The data of the email you sent is displayed below.<br />"; if ($e107_userid) { $message .= "A user-id was detected in the email you sent: <b>" . $e107_userid . "</b><br />"; } // $message .= "<br /><h4>Head</h4>"; // $message .= print_a($head,true); // $message .= "<h4>Emails Found</h4><pre>".print_r($multiArray,TRUE). "</pre>"; $message .= "<pre>" . $strEmail . "</pre>"; if (!empty($this->source)) { echo $message; } else { } } if (!empty($e107_userid)) { if ($errors = $this->setUser_Bounced($e107_userid)) { if ($this->debug === 2) { echo "<h3>Errors</h3>"; print_a($errors); } } } if (!empty($message)) { $eml = array('subject' => "Bounce-Handler : ", 'sender_email' => $pref['siteadminemail'], 'sender_name' => $pref['siteadmin'], 'html' => true, 'template' => 'default', 'body' => $message); e107::getEmail()->sendEmail($pref['siteadminemail'], SITENAME . " :: Bounce-Handler.", $eml); // e107::getEmail()->sendEmail($pref['siteadminemail'], SITENAME." :: Bounce-Handler.", $message, $pref['siteadmin'],$pref['siteadminemail'], $pref['siteadmin']); } return; /* echo "<pre>"; print_r($multiArray); echo "</pre>"; */ foreach ($multiArray as $the) { $the['user_id'] = $head[$identifier]; $the['user_email'] = $the['recipient']; unset($the['recipient']); switch ($the['action']) { case 'failed': e107::getEvent()->trigger('email_bounce_failed', $the); $this->setUser_Bounced(null, $the['user_email']); break; case 'transient': // $num_attempts = delivery_attempts($the['user_email']); e107::getEvent()->trigger('email_bounce_transient', $the); if ($num_attempts > 10) { $this->setUser_Bounced($the['user_id'], $the['user_email']); } else { // insert_into_queue($the['user_email'], ($num_attempts+1)); } break; case 'autoreply': e107::getEvent()->trigger('email_bounce_autoreply', $the); // postpone($the['user_email'], '7 days'); break; default: //don't do anything break; } } }
require_once KNEWS_DIR . "/includes/bouncehandler/bounce_driver.class.php"; $bouncehandler = new Bouncehandler(); if ($inst = knews_pop3_login($knewsOptions['bounce_host'], $knewsOptions['bounce_port'], $knewsOptions['bounce_user'], $knewsOptions['bounce_pass'], "INBOX", $knewsOptions['bounce_ssl'], $knewsOptions['bounce_mode'])) { $stat = knews_pop3_stat($inst); //print_r($stat); //die(); if ($stat['Nmsgs'] > 0) { $messages = $stat['Nmsgs']; if ($messages > 50) { $messages = 50; } $list = knews_pop3_list($inst, $messages); $count = 0; foreach ($list as $row) { $count++; $b = $bouncehandler->get_the_facts($row); $fail_code = 0; $read_blog_id = 0; $posid = strpos($row, 'Knews-Blog-Id:'); $posid = $posid + 14; if ($posid !== false) { $posid2 = strpos($row, '_', $posid); if ($posid2 !== false) { $read_blog_id = substr($row, $posid, $posid2 - $posid); } $read_blog_id = intval(trim($read_blog_id)); } $id_newsletter = 0; $posid = strpos($row, 'Knews-News-Id:'); $posid = $posid + 14; if ($posid !== false) {