Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SMTP Mail Queueing improvements #7788

Merged
2 changes: 2 additions & 0 deletions Sources/ManageMail.php
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ function list_getMailQueue($start, $items_per_page, $sort)
// Private PM/email subjects and similar shouldn't be shown in the mailbox area.
if (!empty($row['private']))
$row['subject'] = $txt['personal_message'];
else
$row['subject'] = mb_decode_mimeheader($row['subject']);

$mails[] = $row;
}
Expand Down
27 changes: 24 additions & 3 deletions Sources/ScheduledTasks.php
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ function ReduceMailQueue($number = false, $override_limit = false, $force_send =

// Now we know how many we're sending, let's send them.
$request = $smcFunc['db_query']('', '
SELECT id_mail, recipient, body, subject, headers, send_html, time_sent, private
SELECT id_mail, recipient, body, subject, headers, send_html, time_sent, private, priority
FROM {db_prefix}mail_queue
ORDER BY priority ASC, id_mail ASC
LIMIT {int:limit}',
Expand All @@ -734,6 +734,7 @@ function ReduceMailQueue($number = false, $override_limit = false, $force_send =
'send_html' => $row['send_html'],
'time_sent' => $row['time_sent'],
'private' => $row['private'],
'priority' => $row['priority'],
);
}
$smcFunc['db_free_result']($request);
Expand Down Expand Up @@ -772,8 +773,18 @@ function ReduceMailQueue($number = false, $override_limit = false, $force_send =

// Send each email, yea!
$failed_emails = array();
$max_priority = 127;
$smtp_expire = 259200;
$priority_offset = 4;
foreach ($emails as $email)
{
// This seems odd, but check the priority if we should try again so soon. Do this so we don't DOS some poor mail server.
if ($email['priority'] > $priority_offset && (time() - $email['time_sent']) % $priority_offset != rand(0, $priority_offset))
{
$failed_emails[] = array($email['to'], $email['body'], $email['subject'], $email['headers'], $email['send_html'], $email['time_sent'], $email['private'], $email['priority']);
continue;
}

if (empty($modSettings['mail_type']) || $modSettings['smtp_host'] == '')
{
$email['subject'] = strtr($email['subject'], array("\r" => '', "\n" => ''));
Expand All @@ -794,11 +805,21 @@ function ReduceMailQueue($number = false, $override_limit = false, $force_send =
else
$result = smtp_mail(array($email['to']), $email['subject'], $email['body'], $email['headers']);

// Old emails should expire
if (!$result && $email['priority'] >= $max_priority)
$result = true;

// Hopefully it sent?
if (!$result)
$failed_emails[] = array($email['to'], $email['body'], $email['subject'], $email['headers'], $email['send_html'], $email['time_sent'], $email['private']);
{
// Determine the "priority" as a way to keep track of SMTP failures.
$email['priority'] = max($priority_offset, $email['priority'], min(ceil((time() - $email['time_sent']) / $smtp_expire * ($max_priority - $priority_offset)) + $priority_offset, $max_priority));

$failed_emails[] = array($email['to'], $email['body'], $email['subject'], $email['headers'], $email['send_html'], $email['time_sent'], $email['private'], $email['priority']);
}
}


// Any emails that didn't send?
if (!empty($failed_emails))
{
Expand Down Expand Up @@ -826,7 +847,7 @@ function ReduceMailQueue($number = false, $override_limit = false, $force_send =
// Add our email back to the queue, manually.
$smcFunc['db_insert']('insert',
'{db_prefix}mail_queue',
array('recipient' => 'string', 'body' => 'string', 'subject' => 'string', 'headers' => 'string', 'send_html' => 'string', 'time_sent' => 'string', 'private' => 'int'),
array('recipient' => 'string', 'body' => 'string', 'subject' => 'string', 'headers' => 'string', 'send_html' => 'string', 'time_sent' => 'string', 'private' => 'int', 'priority' => 'int'),
$failed_emails,
array('id_mail')
);
Expand Down
12 changes: 10 additions & 2 deletions Sources/Subs-Post.php
Original file line number Diff line number Diff line change
Expand Up @@ -1592,9 +1592,17 @@ function server_parse($message, $socket, $code, &$response = null)
if ($code === null)
return substr($server_response, 0, 3);

if (substr($server_response, 0, 3) != $code)
$response_code = (int) substr($server_response, 0, 3);
if ($response_code != $code)
{
log_error($txt['smtp_error'] . $server_response);
// Ignoreable errors that we can't fix should not be logged.
/*
* 550 - cPanel rejected sending due to DNS issues
* 450 - DNS Routing issues
*/
if ($response_code < 500 && $response_code != 450)
log_error($txt['smtp_error'] . $server_response);

return false;
}

Expand Down