added email bounces processing, fixes #44

This commit is contained in:
following 2013-06-03 14:27:15 +02:00
parent 4aa530b274
commit a0172b1e10
10 changed files with 161 additions and 9 deletions

View File

@ -173,4 +173,12 @@
sql("ALTER TABLE `cache_reports` ADD INDEX `userid` (`userid`)");
}
function dbv_108() // automatic email-bounce processiong
{
if (!sql_field_exists('user','last_email_problem'))
sql("ALTER TABLE `user` ADD COLUMN `last_email_problem` datetime default NULL AFTER `email_problems`");
if (!sql_field_exists('user','mailing_problems'))
sql("ALTER TABLE `user` ADD COLUMN `mailing_problems` int(10) unsigned NOT NULL default '0' AFTER `last_email_problem`");
}
?>

View File

@ -111,6 +111,14 @@
// date format
$opt['db']['dateformat'] = 'Y-m-d H:i:s';
// email delivery processing from syslog-ng eventlog DB
$opt['system']['maillog']['syslog_db_host'] = '';
$opt['system']['maillog']['syslog_db_name'] = '';
$opt['system']['maillog']['syslog_db_user'] = '';
$opt['system']['maillog']['syslog_db_password'] = '';
$opt['system']['maillog']['syslog_oc_host'] = ''; // 'host_name' column in syslog DB
$opt['system']['maillog']['syslog_mta'] = 'postfix/smtp'; // 'program' column in syslog DB
/* cookie or session
*
* SAVE_COOKIE = only use cookies

View File

@ -2488,6 +2488,7 @@ INSERT INTO `sys_trans` (`id`, `text`, `last_modified`) VALUES ('2066', 'Open ch
INSERT INTO `sys_trans` (`id`, `text`, `last_modified`) VALUES ('2067', 'Status', '2013-05-28 16:51:40');
INSERT INTO `sys_trans` (`id`, `text`, `last_modified`) VALUES ('2068', 'since June 2013', '2013-05-28 16:51:40');
INSERT INTO `sys_trans` (`id`, `text`, `last_modified`) VALUES ('2069', 'since February 2012', '2013-05-28 16:51:40');
INSERT INTO `sys_trans` (`id`, `text`, `last_modified`) VALUES ('2070', 'One ore more emails to this user could not be delivered. It might be a good idea to additionally log comments on the user\'s geocaches, and/or trying to contact him/her through other channels like a message board account or another geocaching platform.', '2013-05-28 16:51:40');
-- Table sys_trans_ref
SET NAMES 'utf8';
@ -6428,6 +6429,7 @@ INSERT INTO `sys_trans_text` (`trans_id`, `lang`, `text`, `last_modified`) VALUE
INSERT INTO `sys_trans_text` (`trans_id`, `lang`, `text`, `last_modified`) VALUES ('2067', 'DE', 'Status', '2013-04-25 23:00:00');
INSERT INTO `sys_trans_text` (`trans_id`, `lang`, `text`, `last_modified`) VALUES ('2068', 'DE', 'seit Juni 2013', '2013-04-25 23:00:00');
INSERT INTO `sys_trans_text` (`trans_id`, `lang`, `text`, `last_modified`) VALUES ('2069', 'DE', 'seit Februar 2012', '2013-04-25 23:00:00');
INSERT INTO `sys_trans_text` (`trans_id`, `lang`, `text`, `last_modified`) VALUES ('2070', 'DE', 'Eine oder mehrere Emails an diesen Benutzer konnten nicht zugestellt werden. Es könnte ratsam sein, Hinweise zu seinen Caches zusätzlich zu loggen, und ihn ggf. über weitere Adressen wie z.B. Forenaccounts oder andere Geocaching-Plattformen zu kontaktieren.', '2013-04-25 23:00:00');
INSERT INTO `sys_trans_text` (`trans_id`, `lang`, `text`, `last_modified`) VALUES ('1', 'EN', 'Reorder IDs \r', '2010-09-02 00:15:30');
INSERT INTO `sys_trans_text` (`trans_id`, `lang`, `text`, `last_modified`) VALUES ('2', 'EN', 'The database could not be reconnected.', '2010-08-28 11:48:07');
INSERT INTO `sys_trans_text` (`trans_id`, `lang`, `text`, `last_modified`) VALUES ('3', 'EN', 'Testing please do not login', '2010-08-28 11:48:07');
@ -7988,6 +7990,7 @@ INSERT INTO `sys_trans_text` (`trans_id`, `lang`, `text`, `last_modified`) VALUE
INSERT INTO `sys_trans_text` (`trans_id`, `lang`, `text`, `last_modified`) VALUES ('2067', 'EN', 'Status', '2013-04-25 23:00:00');
INSERT INTO `sys_trans_text` (`trans_id`, `lang`, `text`, `last_modified`) VALUES ('2068', 'EN', 'since June 2013', '2013-04-25 23:00:00');
INSERT INTO `sys_trans_text` (`trans_id`, `lang`, `text`, `last_modified`) VALUES ('2069', 'EN', 'since February 2012', '2013-04-25 23:00:00');
INSERT INTO `sys_trans_text` (`trans_id`, `lang`, `text`, `last_modified`) VALUES ('2070', 'EN', 'One ore more emails to this user could not be delivered. It might be a good idea to additionally log comments on the user\'s geocaches, and/or trying to contact him/her through other channels like a message board account or another geocaching platform.', '2013-04-25 23:00:00');
INSERT INTO `sys_trans_text` (`trans_id`, `lang`, `text`, `last_modified`) VALUES ('1', 'ES', 'Reordenar ID', '2010-12-09 00:17:55');
INSERT INTO `sys_trans_text` (`trans_id`, `lang`, `text`, `last_modified`) VALUES ('2', 'ES', 'La base de datos no se pudo conectar.', '2010-12-09 00:17:55');
INSERT INTO `sys_trans_text` (`trans_id`, `lang`, `text`, `last_modified`) VALUES ('3', 'ES', 'En pruebas - por favor, no entre.', '2010-12-09 00:17:55');

View File

@ -522,7 +522,13 @@
INSERT IGNORE INTO `notify_waiting` (`id`, `cache_id`, `user_id`, `type`)
SELECT NULL, nCacheId, `user`.`user_id`, 1 /* notify_new_cache */
FROM `user`
WHERE NOT ISNULL(`user`.`latitude`)
/* After reaching the 5-bounces limit, we try to send new cache notifications
in larger intervals for some more time, and at least on per year.
See also runwatch.php. */
WHERE (`email_problems` < 5
OR (`email_problems` < 10 AND NOW() > IFNULL(`last_email_problem`,'2013-03-01') + INTERVAL 30 DAY)
OR NOW() > IFNULL(`last_email_problem`,'2013-03-01') + INTERVAL 365 DAY)
AND NOT ISNULL(`user`.`latitude`)
AND NOT ISNULL(`user`.`longitude`)
AND `user`.`notify_radius`>0
AND (acos(cos((90-nLatitude) * 3.14159 / 180) * cos((90-`user`.`latitude`) * 3.14159 / 180) + sin((90-nLatitude) * 3.14159 / 180) * sin((90-`user`.`latitude`) * 3.14159 / 180) * cos((nLongitude-`user`.`longitude`) * 3.14159 / 180)) * 6370) <= `user`.`notify_radius`;

View File

@ -11,6 +11,8 @@ CREATE TABLE `user` (
`password` varchar(32) default NULL,
`email` varchar(60) default NULL,
`email_problems` int(10) NOT NULL default '0',
`last_email_problem` datetime default NULL,
`mailing_problems` int(10) unsigned NOT NULL default '0',
`latitude` double NOT NULL,
`longitude` double NOT NULL,
`is_active_flag` tinyint(1) NOT NULL,

View File

@ -51,6 +51,8 @@ class user
$this->reUser->addString('password', null, true);
$this->reUser->addString('email', null, true);
$this->reUser->addString('email_problems', 0, false);
$this->reUser->addDate('last_email_problem', null, true);
$this->reUser->addInt('mailing_problems', 0, false);
$this->reUser->addFloat('latitude', 0, false);
$this->reUser->addFloat('longitude', 0, false);
$this->reUser->addDate('last_modified', time(), true, RE_INSERT_IGNORE);
@ -1173,16 +1175,20 @@ class user
// email bounce processing
function addEmailProblem($licensemail=false)
{
// mailing_problems is a bit-flag field to remember nondelivered, important mailings
if ($licensemail)
return $this->reUser->setValue('email_problems', 1000001) && $this->save();
else
return $this->reUser->setValue('email_problems', $this->getEmailProblems() + 1) && $this->save();
if (!$this->reUser->setValue('mailing_problems', $this->reUser->getValue('mailing_problems') | 1))
return false;
return $this->reUser->setValue('email_problems', $this->getEmailProblems() + 1) &&
$this->reUser->setValue('last_email_problem', date('Y-m-d H:i:s')) &&
$this->save();
}
function getEmailProblems()
{
// see also common.inc.php "SELECT `email_problems`"
return $this->reUser->getValue('email_problems') % 1000000;
return $this->reUser->getValue('email_problems');
}
function getDataLicense()
@ -1198,7 +1204,7 @@ class user
function missedDataLicenseMail()
{
return $this->reUser->getValue('email_problems') > 1000000;
return $this->reUser->getValue('mailing_problems') & 1;
}
function confirmEmailAddress()

View File

@ -56,6 +56,7 @@
$tpl->assign('subject', $subject);
$tpl->assign('text', $text);
$tpl->assign('emailaddress', $bEmailaddress);
$tpl->assign('email_problems', $user->getEmailProblems());
$tpl->assign('userid', $user->getUserId());
$tpl->assign('username', $user->getUsername());

View File

@ -10,7 +10,7 @@
{if $success==true}
<div class="content2-pagetitle">
<img src="resource2/{$opt.template.style}/images/misc/22x22-email.png" style="align: left; margin-right: 10px;" width="32" height="32" alt="" />
<b>{t 1=$smarty.capture.userlink}E-Mail to %1 was sent{/t}</b>
{t 1=$smarty.capture.userlink}E-Mail to %1 was sent{/t}
</div>
<table class="table">
@ -33,10 +33,18 @@
<input type="hidden" name="userid" value="{$userid}"/>
<div class="content2-pagetitle">
<img src="resource2/{$opt.template.style}/images/misc/22x22-email.png" style="align: left; margin-right: 10px;" width="32" height="32" alt="" />
<b>{t 1=$smarty.capture.userlink}Send E-Mail to %1{/t}</b>
{t 1=$smarty.capture.userlink}Send E-Mail to %1{/t}
</div>
<table class="table">
{if $email_problems > 0}
<tr>
<td colspan="2" class="errormsg">
<p>{t}One ore more emails to this user could not be delivered. It might be a good idea to additionally log comments on the user's geocaches, and/or trying to contact him/her through other channels like a message board account or another geocaching platform.{/t}</p>
</td>
</tr>
{/if}
<tr>
<td colspan="2">{t}Subject:{/t} <input type="text" name="subject" value="{$subject|escape}" class="input400"></td>
</tr>

View File

@ -60,6 +60,7 @@
// Benachrichtigung speichern
sql("INSERT IGNORE INTO `watches_notified` (`user_id`, `object_id`, `object_type`, `date_created`) VALUES ('&1', '&2', 1, NOW())", $rNewLog['user_id'], $rNewLog['log_id']);
// Owner notifications are always sent, independent of user.email_problems counter.
process_owner_log($rNewLog['user_id'], $rNewLog['log_id']);
}
mysql_free_result($rsNotified);
@ -77,7 +78,11 @@
{
// Benachrichtigung speichern
sql("INSERT IGNORE INTO `watches_notified` (`user_id`, `object_id`, `object_type`, `date_created`) VALUES ('&1', '&2', 1, NOW())", $rcw['user_id'], $rcw['log_id']);
process_log_watch($rcw['user_id'], $rcw['log_id']);
// Watch notifications are discarded if the user had some undeliverable emails.
// See also stored procedure sp_notify_new_cache().
if (sqlValue("SELECT `email_problems` FROM `user` WHERE `user_id`='" . sql_escape($rcw['user_id']) . "'", 0) < 5)
process_log_watch($rcw['user_id'], $rcw['log_id']);
sql("DELETE FROM `watches_logqueue` WHERE `log_id`='&1' AND `user_id`='&2'", $rcw['log_id'], $rcw['user_id']);
}

View File

@ -0,0 +1,105 @@
<?php
/***************************************************************************
* For license information see doc/license.txt
*
* Unicode Reminder メモ
*
* Process system maillog to detect email delivery problems
***************************************************************************/
checkJob(new maillog());
class maillog
{
var $name = 'maillog';
var $interval = 600; // every 10 minutes
function run()
{
global $opt;
if ($opt['system']['maillog']['syslog_db_host'] != '')
if ($opt['system']['maillog']['syslog_mta'] != 'postfix/smtp')
{
echo $this->name.": unknown MTA '".$opt['system']['maillog']['syslog_mta']."'\n";
return;
}
else
$this->process_syslog();
}
function process_syslog()
{
global $opt;
$dbc = @mysql_connect($opt['system']['maillog']['syslog_db_host'],
$opt['system']['maillog']['syslog_db_user'],
$opt['system']['maillog']['syslog_db_password']);
if ($dbc === FALSE)
{
echo $this->name.": could not connect to syslog database\n";
return;
}
if (@mysql_query("USE ".$opt['system']['maillog']['syslog_db_name']) === FALSE)
{
echo $this->name.": could not open syslog database: ".mysql_error()."\n";
return;
}
$last_id = sql_value("SELECT `value` FROM `sysconfig` WHERE `name`='syslog_maillog_lastid'", 0);
$last_date = sql_value("SELECT `value` FROM `sysconfig` WHERE `name`='syslog_maillog_lastdate'", "");
// We check for both, new IDs and new creation dates, so that it still works
// if the syslog DB is re-setup and IDs restarted from 1 (dates are not unique).
$rs = @mysql_query(
"SELECT `id`, `message`, `created`
FROM `event`
WHERE (`id`>'" . mysql_real_escape_string($last_id) . "' OR `created`>'" . mysql_real_escape_string($last_date) . "')
AND `host_name`='" . mysql_real_escape_string($opt['system']['maillog']['syslog_oc_host']) . "'
AND `program`='" . mysql_real_escape_string($opt['system']['maillog']['syslog_mta']) . "'
ORDER BY `id`");
if ($rs === FALSE)
{
echo $this->name.": syslog query error (".mysql_errno()."): ".mysql_error()."\n";
return;
}
while ($logentry = mysql_fetch_assoc($rs))
{
$message = $logentry['message']; // latin-1 charset
$delivered = strpos($message, 'status=sent') > 0;
$bounced = strpos($message, 'status=bounced') > 0;
if ($delivered || $bounced)
{
if (preg_match('/ to=<(.+)>,/U',$message,$matches))
{
$emailadr = $matches[1];
if ($delivered)
sql("UPDATE `user` SET `email_problems`=0
WHERE `email`='" . mysql_real_escape_string($emailadr) . "'");
else if ($bounced)
// maximum one bounce per day is counted, to filter out temporary problems
sql("UPDATE `user` SET `email_problems`=`email_problems`+1, `last_email_problem`='" . mysql_real_escape_string($logentry['created']) . "'
WHERE `email`='" . mysql_real_escape_string($emailadr) . "'
AND IFNULL(`last_email_problem`,'') < '" . mysql_real_escape_string(substr($logentry['created'],0,10)) . "'");
}
else
echo $this->name.": no email address found for record ID ".$logentry['id']."\n";
}
$last_id = $logentry['id'];
$last_date = $logentry['created'];
}
mysql_free_result($rs);
sql("INSERT INTO `sysconfig` (`name`, `value`) VALUES ('syslog_maillog_lastid','&1')
ON DUPLICATE KEY UPDATE `value`='&1'",
$last_id);
sql("INSERT INTO `sysconfig` (`name`, `value`) VALUES ('syslog_maillog_lastdate','&1')
ON DUPLICATE KEY UPDATE `value`='&1'",
$last_date);
}
}
?>