From c7b4d24e21e30a6f9a23c42de500991b0df59f75 Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 11 Oct 2023 10:33:14 +0800 Subject: [PATCH] Fix #7796 - media outreach crm - needs distributed email sending (due to spam blocks) --- DataObjects/Core_domain.php | 19 +- DataObjects/Core_notify.php | 19 ++ DataObjects/Core_notify_blacklist.php | 26 +++ DataObjects/Core_notify_server.php | 219 +++++++++++++++++++++ DataObjects/pman.links.ini | 9 + Notify.php | 190 +++++++------------ NotifySend.php | 263 +++++++++----------------- 7 files changed, 448 insertions(+), 297 deletions(-) diff --git a/DataObjects/Core_domain.php b/DataObjects/Core_domain.php index 89b4587d..8c6bc832 100644 --- a/DataObjects/Core_domain.php +++ b/DataObjects/Core_domain.php @@ -15,5 +15,22 @@ class Pman_Core_DataObjects_Core_domain extends DB_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - + function loadOrCreate($dom) + { + // should we validate domain? + static $cache = array(); + if (isset($cache[$dom])) { + return $cache[$dom]; + } + + $cd = DB_DataObject::Factory($dom); + if ($cd->get('domain', $dom)) { + $cache[$dom] = $cd; + return $cd; + } + $cd->domain = $dom; + $cd->insert(); + $cache[$dom] = $cd; + return $cd; + } } diff --git a/DataObjects/Core_notify.php b/DataObjects/Core_notify.php index 8c0e6282..09986327 100644 --- a/DataObjects/Core_notify.php +++ b/DataObjects/Core_notify.php @@ -344,5 +344,24 @@ class Pman_Core_DataObjects_Core_notify extends DB_DataObject return true; } + // after called do not rely on content as it includes NOW() + function flagDone($event,$msgid) + { + $ww = clone($this); + if(strtotime($this->act_when) > strtotime("NOW")){ + $this->act_when = $this->sqlValue('NOW()'); + } + $this->sent = $this->sent == '0000-00-00 00:00:00' ? $this->sqlValue('NOW()') :$this->sent; // do not update if sent..... + $this->msgid = ''; + $this->event_id = $event->id; + $this->update($ww); + } + + function flagLater($when) + { + $ww = clone($this); + $this->act_when = $when; + $this->update($ww); + } } diff --git a/DataObjects/Core_notify_blacklist.php b/DataObjects/Core_notify_blacklist.php index 6aa5b8e0..408f542c 100644 --- a/DataObjects/Core_notify_blacklist.php +++ b/DataObjects/Core_notify_blacklist.php @@ -17,6 +17,32 @@ class Pman_Core_DataObjects_Core_notify_blacklist extends DB_DataObject public $added_dt; + function messageIsBlacklisted($err) + { + $match = array( + '5.7.0 DT:SPM'. // 163.com + 'on our block list ', // live.com + 'spameatingmonkey.net', // spameatingmonkey.net (users) + 'sender is listed on the block', // korian? + 'proofpoint.com', // another spam detecotr + 'cloud-security.net', // another spam protector.. + + ); + foreach($match as $str) { + if (strpos($err, $str) !== false) { + return true; + } + } + return false; + } + // delete blacklists older than 1 week (and try again) + function prune() + { + $this->query(" + DELETE FROM {$this->tableName()} where added_dt < NOW() - INTERVAL 1 WEEK + "); + + } } \ No newline at end of file diff --git a/DataObjects/Core_notify_server.php b/DataObjects/Core_notify_server.php index f678e6c0..0e95ea15 100644 --- a/DataObjects/Core_notify_server.php +++ b/DataObjects/Core_notify_server.php @@ -17,7 +17,226 @@ class Pman_Core_DataObjects_Core_notify_server extends DB_DataObject public $is_active; public $last_send; + // most services should call this first.. + function getCurrent($notify) + { + static $current = false;; + + if ($current !== false) { + return $current; + } + + $ns = DB_DataObject::factory('core_notify_server'); + $ns->poolname = $notify->poolname; + $ns->is_active = 1; + $ns->hostname = gethostname(); + if (!$ns->count()) { + $notify->jerr("Server not found for this server " . gethostname() . " in core_notify_server" ); + } + $ns->find(true); + $current = $ns; + return $ns; + } + function isFirstServer() + { + $servers = $this->availableServers(); + if (empty($servers)) { + return false; + } + // only run this on the first server... + return $this->id == $servers[0]->id; + } + + + // called on current server. + function assignQueues($notify) + { + + + $servers = $this->availableServers(); + $ids = array(); + foreach($servers as $s) { + $ids[] = $s->id; + } + + + if (empty($ids)) { + $notify->jerr("no configured servers in core_notify_server for poolname = {$notify->poolname}"); + + } + + // only run this on the first server... + if ($this->id != $ids[0]) { + return; + } + foreach($ids as $rn) { + $up[$rn] = array(); + } + + $num_servers = count($ids); + + if ($num_servers == 1) { + $p = DB_DataObject::factory($notify->table); + $p->query(" + UPDATE + {$notify->table} + SET + server_id = {$ids[0]} + WHERE + sent < '2000-01-01' + and + event_id = 0 + and + act_start < NOW() + INTERVAL 3 HOUR + and + server_id != {$ids[0]} + "); + return; + } + + // ((@row_number := CASE WHEN @row_number IS NULL THEN 0 ELSE @row_number END +1) % {$num_servers}) + + + + $p = DB_DataObject::factory($notify->table); + $p->whereAdd(" + sent < '2000-01-01' + and + event_id = 0 + and + act_start < NOW() + INTERVAL 3 HOUR + and + server_id NOT IN (" . implode(",", $ids) . ") + "); + if ($p->count() < 1) { + return; + } + + $p->selectAdd(); + $p->selectAdd("id, ((@row_number := CASE WHEN @row_number IS NULL THEN 0 ELSE @row_number END +1) % {$num_servers}) as rn"); + $kv = $p->fetchAll('id,rn'); + foreach($kv as $id => $r) { + $up[ $ids[$r] ][] = $id; + } + foreach($up as $sid => $nids) { + $p = DB_DataObject::factory($notify->table); + $p->query(" + UPDATE + {$this->table} + SET + server_id = $sid + WHERE + id IN (". implode(",', $nids"). ')' + ); + } + + DB_DataObject::factory("core_notify_blacklist")->prune(); + + } + // called on current server. + + function availableServers() + { + $ns = DB_DataObject::factory('core_notify_server'); + $ns->poolname = $this->poolname; + $ns->is_active = 1; + $ns->orderBy('id ASC'); + return $ns->fetchAll(); + + } + + function updateNotifyToNextServer( $cn , $when = false, $allow_same = false) + { + // fixme - this should take into account blacklisted - and return false if no more servers are available + $email = empty($cn->to_email) ? ($cn->person() ? $cn->person()->email : $cn->to_email) : $cn->to_email; + + $w = DB_DataObject::factory($cn->tableName()); + $w->get($cn->id); + + $servers = $this->availableServerIds(); + $start = 0; + foreach($servers as $i => $s) { + if ($s->id == $this->id) { + $start = $i; + } + } + + $offset = ($start + 1) % count($ids); + $good = false; + while ($offset != $start) { + $s = $servers[$offset]; + if (!$s->isBlacklisted($email)) { + $good = $s; + break; + } + } + if ($good == false && $allow_same) { + $good = $this; + } + + if ($good == false) { + return false; + } + + + // next server.. + $pp = clone($w); + $w->server_id = $good->id; + $w->act_when = $when === false ? $w->sqlValue('NOW() + INTERVAL 1 MINUTE') : $when; + $w->update($pp); + return true; + } + + + function isBlacklisted($email) + { + // return current server id.. + static $cache = array(); + + // get the domain.. + $ea = explode('@',$email); + $dom = strtolower(array_pop($ea)); + if (isset($cache[$dom])) { + return $cache[$dom]; + } + + $cd = DB_DataObject::factory('core_domain')->loadOrCreate($dom); + + $bl = DB_DataObject::factory('core_notify_blacklist'); + $bl->server_id = $this->id; + $bl->domain_id = $cd->id; + if ($bl->count()) { + $cache[$dom] = true; + return true; + } + + return ralse; + } + function initHelo() + { + + $ff->Mail['helo'] = $this->helo; + + } + function checkSmtpResponse($errmsg, $core_domain) + { + $bl = DB_DataObject::factory('core_notify_blacklist'); + $bl->server_id = $this->id; + $bl->domain_id = $core_domain->id; + if ($bl->count()) { + return; + } + // is it a blacklist message + if (!$bl->messageIsBlacklisted($errmsg)) { + return; + } + $bl->added_dt = $bl->sqlValue("NOW()"); + $bl->insert(); + + + } + } \ No newline at end of file diff --git a/DataObjects/pman.links.ini b/DataObjects/pman.links.ini index ec531e17..d2e550de 100644 --- a/DataObjects/pman.links.ini +++ b/DataObjects/pman.links.ini @@ -65,12 +65,21 @@ watch_id = core_watch:id trigger_person_id = core_person:id trigger_event_id = Events:id domain_id = core_domain:id +server_id = core_notify_server:id + [core_notify_recur] person_id = core_person:id last_event_id = Events:id method_id = core_enum:id + +[core_notify_blacklist] +server_id = core_notify_server:id +domain_id = core_domain:id + + + [core_email] owner_id = core_person:id bcc_group_id = core_group:id diff --git a/Notify.php b/Notify.php index 0e2d6a24..705cb6bc 100644 --- a/Notify.php +++ b/Notify.php @@ -124,11 +124,15 @@ class Pman_Core_Notify extends Pman var $evtype = ''; // any notification... // this script should only handle EMAIL notifications.. - var $server_id; + var $server; // core_notify_server + var $poolname = 'core'; var $opts; var $force = false; + + var $clear_interval = '1 WEEK'; // how long to clear the old queue of items. + function getAuth() { $ff = HTML_FlexyFramework::get(); @@ -181,22 +185,23 @@ class Pman_Core_Notify extends Pman $this->generateNotifications(); - $this->assignQueues(); - - //DB_DataObject::debugLevel(1); + //DB_DataObject::debugLevel(1); $w = DB_DataObject::factory($this->table); $total = 0; $ff = HTML_FlexyFramework::get(); - if (!empty($ff->Core_Notify['servers']) && empty($ff->Core_Notify['servers-non-pool'][gethostname()])) { - - if (!isset($ff->Core_Notify['servers'][gethostname()])) { - $this->jerr("Core_Notify['servers']['" . gethostname() ."'] is not set"); - } - $w->server_id = array_search(gethostname(),array_keys($ff->Core_Notify['servers'])); - } + + + $this->server = DB_DataObject::Factory('core_notify_server')->getCurrent($this); + + $this->server->assignQueues($this); + + + $this->clearOld(); + + if (!empty($this->evtype)) { $w->evtype = $this->evtype; } @@ -286,10 +291,13 @@ class Pman_Core_Notify extends Pman // not sure what happesn if person email and to_email is empty!!? $email = empty($p->to_email) ? ($p->person() ? $p->person()->email : $p->to_email) : $p->to_email; - $black = $this->isBlacklisted($email); + $black = $this->server->isBlacklisted($email); if ($black !== false) { - $this->logecho("DOMAIN blacklisted - {$email} - moving to another pool"); - $this->updateServer($p, $black); + + if (false === $this->server->updateNotifyToNextServer($p)) { + $p->updateState("????"); + } + continue; } @@ -299,8 +307,7 @@ class Pman_Core_Notify extends Pman // push it to a 'domain specific queue' $this->logecho("REQUEING - maxed out that domain - {$email}"); $this->pushQueueDomain($p, $email); - - + //sleep(3); continue; } @@ -311,11 +318,13 @@ class Pman_Core_Notify extends Pman } - $this->logecho("REQUEUING all emails that maxed out:" . count($this->next_queue)); + $this->logecho("REQUEUING all emails that maxed out:" . count($this->next_queue)); if (!empty($this->next_queue)) { foreach($this->next_queue as $p) { - $this->updateServer($p); + if (false === $this->server->updateNotifyToNextServer($p)) { + $p->updateState("????"); + } } } @@ -335,55 +344,10 @@ class Pman_Core_Notify extends Pman } - function isBlacklisted($email) - { - // return current server id.. - $ff = HTML_FlexyFramework::get(); - //$this->logecho("CHECK BLACKLISTED - {$email}"); - if (empty($ff->Core_Notify['servers'])) { - return false; - } - - if (!isset($ff->Core_Notify['servers'][gethostname()]['blacklisted'])) { - return false; - } - - // get the domain.. - $ea = explode('@',$email); - $dom = strtolower(array_pop($ea)); - - //$this->logecho("CHECK BLACKLISTED DOM - {$dom}"); - if (!in_array($dom, $ff->Core_Notify['servers'][gethostname()]['blacklisted'] )) { - return false; - } - //$this->logecho("RETURN BLACKLISTED TRUE"); - return array_search(gethostname(),array_keys($ff->Core_Notify['servers'])); - } + // this sequentially distributes requeued emails.. - to other servers. (can exclude current one if we have that flagged.) - function updateServer($ww, $exclude = -1) - { - $w = DB_DataObject::factory($ww->tableName()); - $w->get($ww->id); - - $ff = HTML_FlexyFramework::get(); - static $num = 0; - if (empty($ff->Core_Notify['servers'])) { - return; - } - $num = ($num+1) % count(array_keys($ff->Core_Notify['servers'])); - if ($exclude == $num ) { - $num = ($num+1) % count(array_keys($ff->Core_Notify['servers'])); - } - // next server.. - $pp = clone($w); - $w->server_id = $num; - - $w->act_when = $w->sqlValue('NOW() + INTERVAL 1 MINUTE'); - $w->update($pp); - - - } + function generateNotifications() @@ -420,65 +384,7 @@ class Pman_Core_Notify extends Pman } - function assignQueues() - { - $ff = HTML_FlexyFramework::get(); - - if (empty($ff->Core_Notify['servers'])) { - return; - } - - if (isset($ff->Core_Notify['servers-non-pool'][gethostname()])) { - return; - } - - if (!isset($ff->Core_Notify['servers'][gethostname()])) { - - $this->jerr("Core_Notify['servers']['" . gethostname() ."'] is not set"); - } - // only run this on the main server... - if (array_search(gethostname(),array_keys($ff->Core_Notify['servers'])) > 0) { - return; - } - - $num_servers = count(array_keys($ff->Core_Notify['servers'])); - $p = DB_DataObject::factory($this->table); - $p->whereAdd(" - sent < '2000-01-01' - and - event_id = 0 - and - act_start < NOW() + INTERVAL 3 HOUR - and - server_id < 0" - - ); - if ($p->count() < 1) { - return; - } - $p = DB_DataObject::factory($this->table); - // 6 seconds on this machne... - $p->query(" - UPDATE - {$this->table} - SET - server_id = ((@row_number := CASE WHEN @row_number IS NULL THEN 0 ELSE @row_number END +1) % {$num_servers}) - WHERE - sent < '2000-01-01' - and - event_id = 0 - and - act_start < NOW() + INTERVAL 3 HOUR - and - server_id < 0 - ORDER BY - id ASC - LIMIT - 10000 - "); - - - } + function run($id, $email='', $cmdOpts="") { @@ -687,7 +593,41 @@ class Pman_Core_Notify extends Pman $this->domain_queue = false; return $ret; } - + function clearOld() + { + if ($this->server->isFirstServer()) { + $p = DB_DataObject::factory($this->table); + $p->whereAdd(" + sent < '2000-01-01' + and + event_id = 0 + and + act_start < NOW() - INTERVAL {$this->clear_interval} + "); + // $p->limit(1000); + if ($p->count()) { + $ev = $this->addEvent('NOTIFY', false, "RETRY TIME EXCEEDED"); + $p = DB_DataObject::factory($this->table); + $p->query(" + UPDATE + {$this->table} + SET + sent = NOW(), + msgid = '', + event_id = {$ev->id} + WHERE + sent < '2000-01-01' + and + event_id = 0 + and + act_start < NOW() - INTERVAL {$this->clear_interval} + LIMIT + 1000 + "); + + } + } + } function output() diff --git a/NotifySend.php b/NotifySend.php index 132930b7..00e61684 100644 --- a/NotifySend.php +++ b/NotifySend.php @@ -71,6 +71,8 @@ class Pman_Core_NotifySend extends Pman ); var $table = 'core_notify'; var $error_handler = 'die'; + var $poolname = 'core'; + var $server; // core_notify_server function getAuth() { @@ -106,6 +108,10 @@ class Pman_Core_NotifySend extends Pman $this->errorHandler("already sent - repeat to early\n"); } + + $this->server = DB_DataObject::Factory('core_notify_server')->getCurrent($this); + + if (!empty($opts['debug'])) { print_r($w); $ff = HTML_FlexyFramework::get(); @@ -119,7 +125,7 @@ class Pman_Core_NotifySend extends Pman if (!$force && (!empty($w->msgid) || $sent)) { $ww = clone($w); - if (!$sent) { + if (!$sent) { // fix sent. $w->sent = $w->sent == '0000-00-00 00:00:00' ? $w->sqlValue('NOW()') :$w->sent; // do not update if sent..... $w->update($ww); } @@ -129,17 +135,10 @@ class Pman_Core_NotifySend extends Pman $o = $w->object(); if ($o === false) { - - $ev = $this->addEvent('NOTIFY', $w, - "Notification event cleared (underlying object does not exist)" );; - $ww = clone($w); - $w->sent = $w->sent == '0000-00-00 00:00:00' ? $w->sqlValue('NOW()') :$w->sent; // do not update if sent..... - $w->msgid = ''; - $w->event_id = $ev->id; - $w->update($ww); - $this->errorHandler(date('Y-m-d h:i:s ') . - "Notification event cleared (underlying object does not exist)" - ."\n"); + + $ev = $this->addEvent('NOTIFY', $w, "Notification event cleared (underlying object does not exist)" ); + $w->flagDone($ev, ''); + $this->errorHandler( $ev->remarks); } @@ -147,32 +146,16 @@ class Pman_Core_NotifySend extends Pman $p = $w->person(); if (isset($p->active) && empty($p->active)) { - $ev = $this->addEvent('NOTIFY', $w, - "Notification event cleared (not user not active any more)" );; - $ww = clone($w); - $w->sent = $w->sent == '0000-00-00 00:00:00' ? $w->sqlValue('NOW()') :$w->sent; // do not update if sent..... - $w->msgid = ''; - $w->event_id = $ev->id; - $w->update($ww); - $this->errorHandler(date('Y-m-d h:i:s ') . - "Notification event cleared (not user not active any more)" - ."\n"); - $this->errorHandler("message has been sent already.\n"); + $ev = $this->addEvent('NOTIFY', $w, "Notification event cleared (not user not active any more)" );; + $w->flagDone($ev, ''); + $this->errorHandler( $ev->remarks); } // has it failed mutliple times.. if (!empty($w->field) && isset($p->{$w->field .'_fails'}) && $p->{$w->field .'_fails'} > 9) { - $ev = $this->addEvent('NOTIFY', $w, - "Notification event cleared (user has to many failures)" );; - $ww = clone($w); - $w->sent = $w->sqlValue('NOW()'); // do not update if sent..... - $w->msgid = ''; - $w->event_id = $ev->id; - $w->update($ww); - $this->errorHandler(date('Y-m-d h:i:s ') . - "Notification event cleared (user has to many failures)" - ."\n"); - $this->errorHandler("user has to many failures.\n"); + $ev = $this->addEvent('NOTIFY', $w, "Notification event cleared (user has to many failures)" );; + $w->flagDone($ev, ''); + $this->errorHandler( $ev->remarks); } // let's work out the last notification sent to this user.. @@ -216,17 +199,9 @@ class Pman_Core_NotifySend extends Pman $email = $this->makeEmail($o, $p, $last, $w, $force); if ($email === true) { - - $ev = $this->addEvent('NOTIFY', $w, - "Notification event cleared (not required any more)" );; - $ww = clone($w); - $w->sent = (!$w->sent || $w->sent == '0000-00-00 00:00:00') ? $w->sqlValue('NOW()') : $w->sent; // do not update if sent..... - $w->msgid = ''; - $w->event_id = $ev->id; - $w->update($ww); - $this->errorHandler(date('Y-m-d h:i:s ') . - "Notification event cleared (not required any more)" - ."\n"); + $ev = $this->addEvent('NOTIFY', $w, "Notification event cleared (not required any more) - toEmail=true" );; + $w->flagDone($ev, ''); + $this->errorHandler( $ev->remarks); } if (is_a($email, 'PEAR_Error')) { $email =array( @@ -243,28 +218,18 @@ class Pman_Core_NotifySend extends Pman if ($email === false || isset($email['error']) || empty($p)) { // object returned 'false' - it does not know how to send it.. - $ev = $this->addEvent('NOTIFYFAIL', $w, isset($email['error']) ? - $email['error'] : "INTERNAL ERROR - We can not handle " . $w->ontable); - $ww = clone($w); - $w->sent = (!$w->sent || $w->sent == '0000-00-00 00:00:00') ? $w->sqlValue('NOW()') : $w->sent; // do not update if sent..... - $w->msgid = ''; - $w->event_id = $ev->id; - $w->to_email = $p->email; - $w->update($ww); - $this->errorHandler(date('Y-m-d h:i:s ') . - (isset($email['error']) ? - $email['error'] : "INTERNAL ERROR - We can not handle " . $w->ontable) - ."\n"); + $ev = $this->addEvent('NOTIFYFAIL', $w, isset($email['error']) ? $email['error'] : "INTERNAL ERROR - We can not handle " . $w->ontable); + $w->flagDone($ev, ''); + $this->errorHandler( $ev->remarks); } if (isset($email['later'])) { - $old = clone($w); - $w->act_when = $email['later']; - $this->updateServer($w); - $w->update($old); - $this->errorHandler(date('Y-m-d h:i:s ') . " Delivery postponed by email creator to {$email['later']}"); + + $this->server->updateNotifyToNextServer($w, $email['later'],true); + + $this->errorHandler("Delivery postponed by email creator to {$email['later']}"); } @@ -291,18 +256,21 @@ class Pman_Core_NotifySend extends Pman // since some of them have spaces?!?! $p->email = trim($p->email); + $core_domain = DB_DataObject::factory('core_domain')->loadOrCreate($dom); + $ww = clone($w); + $ww->to_email = empty($ww->to_email) ? $p->email : $ww->to_email; + $ww->domain_id = $core_domain->id; + // if to_email has not been set!? + $ww->update($w); // if nothing has changed this will not do anything. + $w = clone($ww); + require_once 'Validate.php'; if (!Validate::email($p->email, true)) { $ev = $this->addEvent('NOTIFYFAIL', $w, "INVALID ADDRESS: " . $p->email); - $ww = clone($w); - $w->sent = (!$w->sent || $w->sent == '0000-00-00 00:00:00') ? $w->sqlValue('NOW()') : $w->sent; // do not update if sent..... - $w->msgid = ''; - $w->event_id = $ev->id; - $w->to_email = $p->email; - $w->update($ww); - $this->errorHandler(date('Y-m-d h:i:s ') . "INVALID ADDRESS: " . $p->email. "\n"); + $w->flagDone($ev, ''); + $this->errorHandler($ev->remarks); } @@ -339,19 +307,13 @@ class Pman_Core_NotifySend extends Pman // only retry for 1 day if the MX issue.. if ($retry < 240) { $this->addEvent('NOTIFY', $w, 'MX LOOKUP FAILED ' . $dom ); - $w->act_when = date('Y-m-d H:i:s', strtotime('NOW + ' . $retry . ' MINUTES')); - $this->updateServer($w); - $w->update($ww); - $this->errorHandler(date('Y-m-d h:i:s') . " - MX LOOKUP FAILED {$dom}\n"); + $w->flagLater(date('Y-m-d H:i:s', strtotime('NOW + ' . $retry . ' MINUTES'))); + $this->errorHandler($ev->remarks); } $ev = $this->addEvent('NOTIFYFAIL', $w, "BAD ADDRESS - BAD DOMAIN - ". $p->email ); - $w->sent = $w->sqlValue('NOW()'); // why not updated - used to leave as is? - $w->msgid = ''; - $w->event_id = $ev->id; - $w->to_email = $p->email; - $w->update($ww); - $this->errorHandler(date('Y-m-d h:i:s') . " - FAILED - BAD DOMAIN - {$p->email} \n"); + $w->flagDone($ev, ''); + $this->errorHandler($ev->remarks); } @@ -361,17 +323,11 @@ class Pman_Core_NotifySend extends Pman if (!$force && strtotime($w->act_start) < strtotime('NOW - 3 DAY')) { $ev = $this->addEvent('NOTIFYFAIL', $w, "BAD ADDRESS - GIVE UP - ". $p->email ); - $w->sent = $w->sqlValue('NOW()'); - $w->msgid = ''; - $w->event_id = $ev->id; - $w->to_email = $p->email; - $w->update($ww); - $this->errorHandler(date('Y-m-d h:i:s') . " - FAILED - GAVE UP TO OLD - {$p->email} \n"); + $w->flagDone($ev, ''); + $this->errorHandler( $ev->remarks); } - - $w->to_email = $p->email; //$this->addEvent('NOTIFY', $w, 'GREYLISTED ' . $p->email . ' ' . $res->toString()); // we can only update act_when if it has not been sent already (only happens when running in force mode..) // set act when if it's empty... @@ -384,17 +340,8 @@ class Pman_Core_NotifySend extends Pman $fail = false; require_once 'Mail.php'; - $core_domain = DB_DataObject::factory('core_domain'); - if(!$core_domain->get('domain', $dom)){ - $core_domain = DB_DataObject::factory('core_domain'); - $core_domain->setFrom(array( - 'domain' => $dom - )); - $core_domain->insert(); - } - - $this->initHelo(); + $this->server->initHelo(); if (!isset($ff->Mail['helo'])) { $this->errorHandler("config Mail[helo] is not set"); @@ -446,16 +393,14 @@ class Pman_Core_NotifySend extends Pman $core_notify = DB_DataObject::factory($this->table); $core_notify->domain_id = $core_domain->id; + $core_notify->server_id = $this->server->id; $core_notify->whereAdd(" sent >= NOW() - INTERVAL $seconds SECOND "); if($core_notify->count()){ - $old = clone($w); - $w->act_when = date("Y-m-d H:i:s", time() + $seconds); - $this->updateServer($w); - $w->update($old); - $this->errorHandler(date('Y-m-d h:i:s ') . " Too many emails sent by {$dom}"); + $this->server->updateNotifyToNextServer( $w , date("Y-m-d H:i:s", time() + $seconds), true); + $this->errorHandler( " Too many emails sent by {$dom} - requeing"); } @@ -490,40 +435,30 @@ class Pman_Core_NotifySend extends Pman $ev = $this->addEvent($successEventName, $w, "{$w->to_email} - {$email['headers']['Subject']}"); $ev->writeEventLog($this->debug_str); + + $w->flagDone($ev,$email['headers']['Message-Id']); - if(strtotime($w->act_when) > strtotime("NOW")){ - $w->act_when = date('Y-m-d H:i:s'); - } - - $w->sent = (!$w->sent || $w->sent == '0000-00-00 00:00:00') ? $w->sqlValue('NOW()') : $w->sent; // do not update if sent..... - $w->msgid = $email['headers']['Message-Id']; - $w->event_id = $ev->id; // sent ok.. - no need to record it.. - $w->domain_id = $core_domain->id; - $w->update($ww); - + // enable cc in notify.. if (!empty($email['headers']['Cc'])) { $cmailer = Mail::factory('smtp', isset($ff->Mail) ? $ff->Mail : array() ); $email['headers']['Subject'] = "(CC): " . $email['headers']['Subject']; - $cmailer->send($email['headers']['Cc'], - $email['headers'], $email['body']); + $cmailer->send($email['headers']['Cc'], $email['headers'], $email['body']); } if (!empty($email['bcc'])) { $cmailer = Mail::factory('smtp', isset($ff->Mail) ? $ff->Mail : array() ); $email['headers']['Subject'] = "(CC): " . $email['headers']['Subject']; - $res = $cmailer->send($email['bcc'], - $email['headers'], $email['body']); + $res = $cmailer->send($email['bcc'], $email['headers'], $email['body']); if (!$res || is_a($res, 'PEAR_Error')) { echo "could not send bcc..\n"; } else { echo "Sent BCC to {$email['bcc']}\n"; } } - - - $this->errorHandler(date('Y-m-d h:i:s') . " - SENT {$w->id} - {$w->to_email} \n", true); + + $this->errorHandler( " SENT {$w->id} - {$w->remarks}", true); } // what type of error.. $code = empty($res->userinfo['smtpcode']) ? -1 : $res->userinfo['smtpcode']; @@ -547,54 +482,59 @@ class Pman_Core_NotifySend extends Pman } //print_r($res); $this->addEvent('NOTIFY', $w, 'GREYLISTED - ' . $errmsg); - $w->act_when = date('Y-m-d H:i:s', strtotime('NOW + ' . $retry . ' MINUTES')); - $this->updateServer($w); - $w->domain_id = $core_domain->id; - $w->update($ww); + $this->server->updateNotifyToNextServer($w, strtotime('NOW + ' . $retry . ' MINUTES'),true); - $this->errorHandler(date('Y-m-d h:i:s') . " - GREYLISTED - $errmsg \n"); + $this->errorHandler( $ev->remarks); } + $fail = true; break; } - if ($fail || $next_try_min > (2*24*60)) { - // fail.. = log and give up.. - $errmsg= $fail ? ($res->userinfo['smtpcode'] . ': ' .$res->toString()) : " - UNKNOWN ERROR"; + + // after trying all mxs - could not connect... + if (!$fail && ($next_try_min > (2*24*60) || strtotime($w->act_start) < strtotime('NOW - 3 DAYS'))) { + + $errmsg= " - UNKNOWN ERROR"; if (isset($res->userinfo['smtptext'])) { $errmsg= $res->userinfo['smtpcode'] . ':' . $res->userinfo['smtptext']; } - $ev = $this->addEvent('NOTIFYFAIL', $w, ($fail ? "FAILED - " : "RETRY TIME EXCEEDED - ") . - $errmsg); - $w->sent = (!$w->sent || $w->sent == '0000-00-00 00:00:00') ? $w->sqlValue('NOW()') : $w->sent; // do not update if sent..... - $w->msgid = ''; - $w->event_id = $ev->id; - $w->domain_id = $core_domain->id; - $w->update($ww); - $this->errorHandler(date('Y-m-d h:i:s') . ' - FAILED - '. ($fail ? $res->toString() : "RETRY TIME EXCEEDED\n")); + $ev = $this->addEvent('NOTIFYFAIL', $w, "RETRY TIME EXCEEDED - " . $errmsg); + $w->flagDone($ev, ''); + $this->errorHandler( $ev->remarks); } - // handle no host availalbe forever... - if (strtotime($w->act_start) < strtotime('NOW - 3 DAYS')) { - $ev = $this->addEvent('NOTIFYFAIL', $w, "RETRY TIME EXCEEDED - ". $p->email); - $w->sent = (!$w->sent || $w->sent == '0000-00-00 00:00:00') ? $w->sqlValue('NOW()') : $w->sent; // do not update if sent..... - $w->msgid = ''; - $w->event_id = $ev->id; - $w->domain_id = $core_domain->id; - $w->update($ww); - $this->errorHandler(date('Y-m-d h:i:s') . " - FAILED - RETRY TIME EXCEEDED\n"); + if ($fail) { //// !!!!<<< BLACKLIST DETECT? + // fail.. = log and give up.. + $errmsg= $res->userinfo['smtpcode'] . ': ' .$res->toString(); + if (isset($res->userinfo['smtptext'])) { + $errmsg= $res->userinfo['smtpcode'] . ':' . $res->userinfo['smtptext']; + } + + $ev = $this->addEvent('NOTIFYFAIL', $w, ($fail ? "FAILED - " : "RETRY TIME EXCEEDED - ") . $errmsg); + $w->flagDone($ev, ''); + + if ($res->userinfo['smtpcode'] == 550) { + $this->server->checkSmtpResponse($errmsg, $core_domain); + } + + + $this->errorHandler( $ev->remarks); } + // at this point we just could not find any MX records.. - $this->addEvent('NOTIFY', $w, 'NO HOST CAN BE CONTACTED:' . $p->email); - $w->act_when = date('Y-m-d H:i:s', strtotime('NOW + ' . $retry . ' MINUTES')); - $this->updateServer($w); + // try again. - $w->domain_id = $core_domain->id; - $w->update($ww); - $this->errorHandler(date('Y-m-d h:i:s') ." - NO HOST AVAILABLE\n"); + $ev = $this->addEvent('NOTIFY', $w, 'NO HOST CAN BE CONTACTED:' . $p->email); + + $this->server->updateNotifyToNextServer($w, strtotime('NOW + ' . $retry . ' MINUTES'),true); + + + + $this->errorHandler($ev->remarks); } @@ -704,7 +644,7 @@ class Pman_Core_NotifySend extends Pman throw new Pman_Core_NotifySend_Exception_Fail($msg); } - die($msg); + die(date('Y-m-d h:i:s') . ' ' . $msg ."\n"); } @@ -725,25 +665,6 @@ class Pman_Core_NotifySend extends Pman } - function initHelo() - { - $ff = HTML_FlexyFramework::get(); - - if (isset($ff->Core_Notify['servers-non-pool']) && - isset($ff->Core_Notify['servers-non-pool'][gethostname()]) && - isset($ff->Core_Notify['servers-non-pool'][gethostname()]['helo']) ) { - $ff->Mail['helo'] = $ff->Core_Notify['servers-non-pool'][gethostname()]['helo']; - return; - } - - if (empty($ff->Core_Notify['servers'])) { - return; - } - if (!isset($ff->Core_Notify['servers'][gethostname()]) || !isset($ff->Core_Notify['servers'][gethostname()]['helo']) ) { - $this->jerr("Core_Notify['servers']['" . gethostname() . "']['helo'] not set"); - } - $ff->Mail['helo'] = $ff->Core_Notify['servers'][gethostname()]['helo']; - - } + } \ No newline at end of file -- 2.39.2