Source of file NewsletterBounceTask.php
Size: 8,416 Bytes - Last Modified: 2021-12-23T10:42:19+00:00
/var/www/docs.ssmods.com/process/src/code/tasks/NewsletterBounceTask.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 | <?php /** * Class NewsletterBounceTask * * Handle newsletter bounces from an IMAP box. */ class NewsletterBounceTask extends BuildTask { /** * @var string */ private static $email = ''; /** * @var string */ private static $password = ''; /** * @var string */ private static $server = ''; /** * @var int */ private static $blacklistLimit = 5; /** * @var string */ private static $errorName = ''; /** * @var string */ private static $errorValue = ''; /** * @var string */ private static $diagnosticCode = 'Diagnostic-Code'; /** * @var string */ protected $title = 'Mark bounced newsletter emails'; /** * @var string */ protected $description = "Opens up an e-mail inbox and looks for bounces."; /** * @var bool */ protected $debug = true; /** * @var int $bounces amount of bounces count. */ protected $bounces = 0; /** * @param $request */ public function run($request) { $this->debug = Config::inst()->get('NewsletterBounceTask', 'debug'); $server = Config::inst()->get('NewsletterBounceTask', 'server'); $userName = Config::inst()->get('NewsletterBounceTask', 'email'); $password = Config::inst()->get('NewsletterBounceTask', 'password'); /** @var resource $mailbox */ $mailbox = imap_open($server, $userName, $password); if ($mailbox) { $emails = imap_search($mailbox, 'UNFLAGGED', SE_UID); if ($emails) { foreach ($emails as $emailID) { $emailFlags = imap_fetch_overview($mailbox, $emailID); $isBounce = array(false, false, false); if ($this->debug) { echo "$emailID<hr /><pre>"; } if (!$emailFlags[0]->flagged) { // extra check to make sure we're not checking an already checked e-mail. $isBounce = $this->checkEmail($mailbox, $emailID); } if ($isBounce[0] && $isBounce[1]) { // Only check if the isBounce returns something useful. Error messages are not important. $this->isBounced($mailbox, $emailID, $isBounce); } if ($this->debug) { echo "<hr /></pre>"; } } } imap_close($mailbox, CL_EXPUNGE); // Close the connection and really delete the messages echo $this->bounces . " Bounces found"; } else { user_error("Can not find mailbox", E_USER_NOTICE); } } /** * @param resource $mailbox * @param int $emailID * @return array */ private function checkEmail($mailbox, $emailID) { $bounce = false; $to = false; $error = false; $headers = imap_body($mailbox, $emailID, FT_UID); $headers = explode("\n", $headers); $errorName = Config::inst()->get('NewsletterBounceTask', 'errorName'); $errorValue = Config::inst()->get('NewsletterBounceTask', 'errorValue'); $diagnosticCode = Config::inst()->get('NewsletterBounceTask', 'diagnosticCode'); // I think this can be made smaller? foreach ($headers as $header) { $header = explode(':', $header); if (count($header) == 2) { list($name, $value) = $header; // Strip the spaces at frond and end, they break the other if statements. $name = trim($name); $value = trim($value); if ($this->debug) { echo "$name<br />$value"; } if ($name == $errorName && $value == $errorValue) { // Only true if the error is actually an error. $bounce = true; } if ($name == "To") { // This one is always good $to = Convert::raw2sql($value); } if ($name == $diagnosticCode) { $error = $value; } if ($bounce && $to && $error) { break; // Break when we have a bouncer, a $to and a useful $error. The useful error can be skipped, it'll be false. } } } return (array( $bounce, $to, $error )); } /** * @param $mailbox * @param $emailID * @param $isBounce */ private function isBounced($mailbox, $emailID, $isBounce) { $stripTags = array( '<', '>' ); // Some servers reply with "<user@mail.com>", so, let's strip that. $to = str_replace($stripTags, array('', ''), $isBounce[1]); $error = $isBounce[2]; /** @var Recipient $recipient */ $recipient = Recipient::get() ->filter(array("Email" => $to)) ->first(); if ($recipient->BouncedCount == self::$blacklistLimit) { // When we reach the blacklistLimit, just blacklist this address. $recipient->BlacklistedEmail = true; $recipient->write(); } else { // Otherwise, just up the bouncedCount. $recipient->BouncedCount = $recipient->BouncedCount + 1; $recipient->write(); /** @var NewsletterEmailBounceRecord $record Record this bounce in the NewsletterEmailBounceRecord class. */ $record = NewsletterEmailBounceRecord::get() ->filter(array("BounceEmail" => $to)); if (!$record->count()) { $record = NewsletterEmailBounceRecord::create(); $record->BounceEmail = $to; $record->BounceMessage = $error; $record->RecipientID = $recipient->ID; } else { $record = $record->first(); } $record->LastBounceTime = SS_Datetime::create()->now(); $record->write(); } // Set the e-mail flag imap_setflag_full($mailbox, $emailID, '\flagged', ST_UID); // Also mark it for deletion. imap_delete($mailbox, $emailID, ST_UID); // And up the bounces counter. $this->bounces = $this->bounces + 1; } /** * @return string */ public static function getEmail() { return self::$email; } /** * @param string $email */ public static function setEmail($email) { self::$email = $email; } /** * @return string */ public static function getPassword() { return self::$password; } /** * @param string $password */ public static function setPassword($password) { self::$password = $password; } /** * @return string */ public static function getServer() { return self::$server; } /** * @param string $server */ public static function setServer($server) { self::$server = $server; } /** * @return int */ public static function getBlacklistLimit() { return self::$blacklistLimit; } /** * @param int $blacklistLimit */ public static function setBlacklistLimit($blacklistLimit) { self::$blacklistLimit = $blacklistLimit; } /** * @return string */ public static function getErrorName() { return self::$errorName; } /** * @param string $errorName */ public static function setErrorName($errorName) { self::$errorName = $errorName; } /** * @return string */ public static function getErrorValue() { return self::$errorValue; } /** * @param string $errorValue */ public static function setErrorValue($errorValue) { self::$errorValue = $errorValue; } /** * @return string */ public static function getDiagnosticCode() { return self::$diagnosticCode; } /** * @param string $diagnosticCode */ public static function setDiagnosticCode($diagnosticCode) { self::$diagnosticCode = $diagnosticCode; } } |