Commit fdbd8135 authored by Matthias Larisch's avatar Matthias Larisch

Stop sending to bouncing addresses

parent 6fd50f3a
Pipeline #44287294 passed with stages
in 16 minutes and 37 seconds
......@@ -10,6 +10,7 @@
- add security headers !633 @nicksellen
- changed tile maps to wikimedia !639 @alex.simm
- Use typeahead-address-photon for address autocomplete. Update leaflet and typeahead for recent NPM versions in the same go !640 @NerdyProjects
- Do not send emails to bouncing addresses !645 @NerdyProjects
## Bugfixes
- Improve/correct user profile badge count !612 @pmayd
......
......@@ -4,6 +4,6 @@ CREATE TABLE IF NOT EXISTS `fs_email_bounces` (
`bounce_category` VARCHAR(255) NOT NULL
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8;
DEFAULT CHARSET = utf8mb4;
ALTER TABLE `fs_email_bounces` ADD index `email` (email);
......@@ -24,7 +24,8 @@ class AsyncMail
'body' => '',
'html' => false,
'subject' => DEFAULT_EMAIL_NAME,
'identifier' => '');
'identifier' => '',
'queuedAt' => new \DateTime());
}
public function addRecipient($email, $name = null)
......
......@@ -3,7 +3,7 @@
namespace Foodsharing\Lib\Mail;
use BounceMailHandler\BounceMailHandler;
use Foodsharing\Modules\Email\EmailGateway;
use Foodsharing\Modules\Mails\MailsGateway;
class BounceProcessing
{
......@@ -13,10 +13,10 @@ class BounceProcessing
private $numBounces;
public function __construct(BounceMailHandler $bounceMailHandler, EmailGateway $emailGateway)
public function __construct(BounceMailHandler $bounceMailHandler, MailsGateway $mailsGateway)
{
$this->bounceMailHandler = $bounceMailHandler;
$this->emailGateway = $emailGateway;
$this->mailsGateway = $mailsGateway;
$this->numBounces = 0;
}
......@@ -37,7 +37,7 @@ class BounceProcessing
public function handleBounce($msgnum, $bounceType, $email, $subject, $xheader, $remove, $ruleNo = false, $ruleCat = false, $totalFetched = 0, $body = '', $headerFull = '', $bodyFull = '')
{
if ($bounceType !== false) {
$this->emailGateway->addBounceForMail($email, $ruleCat, new \DateTime());
$this->mailsGateway->addBounceForMail($email, $ruleCat, new \DateTime());
++$this->numBounces;
}
}
......
......@@ -157,13 +157,4 @@ class EmailGateway extends BaseGateway
return $row;
}
public function addBounceForMail($email, $category, \DateTime $time)
{
$this->db->insert('fs_email_bounces', [
'email' => $email,
'bounce_category' => $category,
'bounced_at' => $time->format('Y-m-d H:i:s')
]);
}
}
......@@ -6,6 +6,7 @@ use Ddeboer\Imap\Server;
use Flourish\fEmail;
use Flourish\fFile;
use Flourish\fSMTP;
use Foodsharing\Lib\Db\Db;
use Foodsharing\Modules\Console\ConsoleControl;
use Foodsharing\Modules\Core\Database;
use Foodsharing\Modules\Core\InfluxMetrics;
......@@ -18,17 +19,19 @@ class MailsControl extends ConsoleControl
*/
public static $smtp = false;
public static $last_connect;
private $mailsGateway;
private $mailboxModel;
private $database;
private $metrics;
public function __construct(MailsModel $model, MailboxModel $mailboxModel, Database $database, InfluxMetrics $metrics)
public function __construct(Db $model, MailsGateway $mailsGateway, MailboxModel $mailboxModel, Database $database, InfluxMetrics $metrics)
{
echo "creating mailscontrl!!!!\n";
error_reporting(E_ALL);
ini_set('display_errors', '1');
self::$smtp = false;
$this->model = $model;
$this->mailsGateway = $mailsGateway;
$this->mailboxModel = $mailboxModel;
$this->database = $database;
$this->metrics = $metrics;
......@@ -102,10 +105,10 @@ class MailsControl extends ConsoleControl
continue;
}
$mb_ids = $this->model->getMailboxIds($mboxes);
$mb_ids = $this->mailsGateway->getMailboxIds($mboxes);
if (!$mb_ids) {
$mb_ids = $this->model->getMailboxIds(array('lost'));
$mb_ids = $this->mailsGateway->getMailboxIds(array('lost'));
++$stats['unknown-recipient'];
}
......@@ -195,7 +198,7 @@ class MailsControl extends ConsoleControl
$from['personal'] = $msg->getFrom()->getName();
}
$this->model->saveMessage(
$this->mailsGateway->saveMessage(
$id, // mailbox id
1, // folder
json_encode($from), // sender
......@@ -298,7 +301,7 @@ class MailsControl extends ConsoleControl
public function handleEmail($data)
{
self::info('mail arrived ...: ' . $data['from'][0] . '@' . $data['from'][1]);
self::info('Mail from: ' . $data['from'][0] . ' (' . $data['from'][1] . ')');
$email = new fEmail();
$email->setFromEmail($data['from'][0], $data['from'][1]);
$subject = preg_replace('/\s+/', ' ', trim($data['subject']));
......@@ -319,15 +322,18 @@ class MailsControl extends ConsoleControl
$has_recip = false;
foreach ($data['recipients'] as $r) {
$r[0] = strtolower($r[0]);
self::info($r[0]);
self::info('To: ' . $r[0]);
$address = explode('@', $r[0]);
if (count($address) != 2) {
self::error('invalid address');
continue;
}
$email->addRecipient($r[0], $r[1]);
$has_recip = true;
if (!$this->mailsGateway->emailIsBouncing($r[0])) {
$email->addRecipient($r[0], $r[1]);
$has_recip = true;
} else {
self::error('bouncing address');
}
}
if (!$has_recip) {
return true;
......@@ -338,7 +344,7 @@ class MailsControl extends ConsoleControl
self::smtpReconnect();
}
$max_try = 3;
$max_try = 2;
$sended = false;
while (!$sended) {
--$max_try;
......
<?php
namespace Foodsharing\Modules\Mails;
use Foodsharing\Modules\Core\BaseGateway;
class MailsGateway extends BaseGateway
{
public function saveMessage(
$mailbox_id, // mailbox id
$folder, // folder
$from, // sender
$to, // to
$subject, // subject
$body,
$html,
$time, // time,
$attach = '', // attachements
$read = 0,
$answer = 0)
{
return $this->db->insert('fs_mailbox_message', [
'mailbox_id' => $mailbox_id,
'folder' => $folder,
'sender' => strip_tags($from),
'to' => strip_tags($to),
'subject' => strip_tags($subject),
'body' => strip_tags($body),
'body_html' => $html,
'time' => $time,
'attach' => $attach,
'read' => $read,
'answer' => $answer
]);
}
public function getMailboxIds($mb_names)
{
return $this->db->fetchAllValues('
SELECT id FROM fs_mailbox WHERE `name` IN (' . $this->db->generatePlaceholders(count($mb_names)) . ')',
$mb_names);
}
public function addBounceForMail($email, $category, \DateTime $time)
{
$this->db->insert('fs_email_bounces', [
'email' => $email,
'bounce_category' => $category,
'bounced_at' => $time->format('Y-m-d H:i:s')
]);
}
public function emailIsBouncing($email)
{
$softBounceCount = 0;
$bounces = $this->db->fetchAllByCriteria('fs_email_bounces', [
'bounce_category',
'bounced_at'
], [
'email' => $email
]
);
foreach ($bounces as $bounce) {
$bounce_time = new \DateTime($bounce['bounced_at']);
if (in_array($bounce['bounce_category'], ['full', 'autoreply', 'outofoffice', 'internal_error'])) {
if ($bounce_time > new \DateTime('-1 month')) {
++$softBounceCount;
if ($softBounceCount >= 2) {
return true;
}
}
} else {
return true;
}
}
return false;
}
}
<?php
namespace Foodsharing\Modules\Mails;
use Foodsharing\Lib\Db\Db;
class MailsModel extends Db
{
public function saveMessage(
$mailbox_id, // mailbox id
$folder, // folder
$from, // sender
$to, // to
$subject, // subject
$body,
$html,
$time, // time,
$attach = '', // attachements
$read = 0,
$answer = 0)
{
return $this->insert('
INSERT INTO `fs_mailbox_message`
(
`mailbox_id`,
`folder`,
`sender`,
`to`,
`subject`,
`body`,
`body_html`,
`time`,
`attach`,
`read`,
`answer`
)
VALUES
(
' . (int)$mailbox_id . ',
' . (int)$folder . ',
' . $this->strval($from) . ',
' . $this->strval($to) . ',
' . $this->strval($subject) . ',
' . $this->strval($body) . ',
' . $this->strval($html, true) . ',
' . $this->strval($time) . ',
' . $this->strval($attach) . ',
' . (int)$read . ',
' . (int)$answer . '
)
');
}
public function getMailboxId($mb_name)
{
return $this->qOne('
SELECT id FROM fs_mailbox WHERE `name` = ' . $this->strval($mb_name) . '
');
}
public function getMailboxIds($mb_names)
{
$where = array();
foreach ($mb_names as $n) {
$where[] = $this->strval($n);
}
return $this->qCol('
SELECT id FROM fs_mailbox WHERE `name` IN(' . implode(',', $where) . ')
');
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment