jenkins-bot has submitted this change and it was merged.
Change subject: Add status codes parsing to BounceHandler regex checks
......................................................................
Add status codes parsing to BounceHandler regex checks
Extension now looks for status code returned by SMTP server and differentiates
between permanent and temporary failures. Sticks to RFC3464 whenever possible
and uses heuristic way to obtain the status code otherwise
If we get an 'X-Failed-Recipient' header in the first go, just mark the bounce
as a permanent one, else go for the heuristic method
Change-Id: Ice9d580ba81d7f3575a37267e97f33a9dafdcef5
---
M includes/ProcessBounceEmails.php
M includes/ProcessBounceWithRegex.php
M tests/ProcessBounceWithRegexTest.php
A tests/bounce_emails/emailStatus1
A tests/bounce_emails/emailStatus2
A tests/bounce_emails/emailStatus3
6 files changed, 287 insertions(+), 7 deletions(-)
Approvals:
CSteipp: Looks good to me, but someone else must approve
01tonythomas: Looks good to me, approved
Legoktm: Looks good to me, but someone else must approve
jenkins-bot: Verified
diff --git a/includes/ProcessBounceEmails.php b/includes/ProcessBounceEmails.php
index 2151161..9a53b91 100644
--- a/includes/ProcessBounceEmails.php
+++ b/includes/ProcessBounceEmails.php
@@ -164,11 +164,18 @@
* @return bool
*/
protected function checkPermanentFailure( $emailHeaders ) {
- $permanentFailure = $emailHeaders[ 'x-failed-recipients' ];
- if ( $permanentFailure == null ) {
- return false;
- } else {
+ if ( isset( $emailHeaders['status'] ) ) {
+ $status = explode( '.', $emailHeaders['status'] );
+ // According to RFC1893 status codes starting with 5
mean Permanent Failures
+ return $status[0] == 5;
+ } elseif ( isset( $emailHeaders['smtp-code'] ) ) {
+ return $emailHeaders['smtp-code'] >= 500;
+ } elseif ( isset( $emailHeaders['x-failed-recipients'] ) ) {
+ // If not status code was found, let's presume that the
presence of
+ // X-Failed-Recipients means permanent failure
return true;
+ } else {
+ return false;
}
}
diff --git a/includes/ProcessBounceWithRegex.php
b/includes/ProcessBounceWithRegex.php
index 3baa582..9356195 100644
--- a/includes/ProcessBounceWithRegex.php
+++ b/includes/ProcessBounceWithRegex.php
@@ -26,6 +26,49 @@
}
/**
+ * Parse the single part of delivery status message
+ *
+ * @param string[] $partLines array of strings that contain single
lines of the email part
+ * @return string|null String that contains the status code or null if
it wasn't found
+ */
+ private function parseMessagePart( $partLines ) {
+ foreach ( $partLines as $partLine ) {
+ if ( preg_match( '/^Content-Type: (.+)/', $partLine,
$contentTypeMatch ) ) {
+ if ( $contentTypeMatch[1] !=
'message/delivery-status' ) {
+ break;
+ }
+ }
+ if ( preg_match( '/^Status: (\d\.\d{1,3}\.\d{1,3})/',
$partLine, $statusMatch ) ) {
+ return $statusMatch[1];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Parse the multi-part delivery status message (DSN) according to
RFC3464
+ *
+ * @param string[] $emailLines array of strings that contain single
lines of the email
+ * @return string|null String that contains the status code or null if
it wasn't found
+ */
+ private function parseDeliveryStatusMessage( $emailLines ) {
+ for ( $i = 0; $i < count( $emailLines ) - 1; ++$i ) {
+ $line = $emailLines[$i] . "\n" . $emailLines[$i + 1];
+ if ( preg_match( '/Content-Type:
multipart\/report;\s*report-type=delivery-status;' .
+ '\s*boundary="(.+?)"/', $line,
$contentTypeMatch ) ) {
+ $partIndices = array_keys( $emailLines,
"--$contentTypeMatch[1]" );
+ foreach ( $partIndices as $index ) {
+ $result = $this->parseMessagePart(
array_slice( $emailLines, $index ) );
+ if ( !is_null( $result ) ) {
+ return $result;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
* Extract headers from the received bounce
*
* @param string $email
@@ -51,9 +94,27 @@
// Empty line denotes that the header part is
finished
break;
}
- if ( trim( $emailLine ) == "" ) {
- // Empty line denotes that the header part is
finished
- break;
+ }
+ $status = $this->parseDeliveryStatusMessage( $emailLines );
+ if ( !is_null( $status ) ) {
+ $emailHeaders['status'] = $status;
+ }
+
+ // If the x-failed-recipient header or status code was not
found, we should fallback to a heuristic scan
+ // of the message for a SMTP status code
+ if ( !isset( $emailHeaders['status'] ) && !isset(
$emailHeaders['x-failed-recipients'] ) ) {
+ foreach ( $emailLines as $emailLine ) {
+ if ( preg_match(
'/^\s*(?:(?P<smtp>[1-5]\d{2})[^\d\w.]+)?' .
+
'(?P<status>[245]\.\d{1,3}\.\d{1,3})?\b/', $emailLine, $statusMatch ) ) {
+ if ( isset( $statusMatch['smtp'] ) ) {
+ $emailHeaders['smtp-code'] =
$statusMatch['smtp'];
+ break;
+ }
+ if ( isset( $statusMatch['status'] ) ) {
+ $emailHeaders['status'] =
$statusMatch['status'];
+ break;
+ }
+ }
}
}
return $emailHeaders;
diff --git a/tests/ProcessBounceWithRegexTest.php
b/tests/ProcessBounceWithRegexTest.php
index 34540c1..30f00cb 100644
--- a/tests/ProcessBounceWithRegexTest.php
+++ b/tests/ProcessBounceWithRegexTest.php
@@ -18,6 +18,33 @@
);
}
+ public static function provideBounceStatusEmails() {
+ $email1 = file_get_contents( __DIR__
.'/bounce_emails/emailStatus1' );
+ $email2 = file_get_contents( __DIR__
.'/bounce_emails/emailStatus2' );
+ $email3 = file_get_contents( __DIR__
.'/bounce_emails/emailStatus3' );
+
+ return array(
+ array(
+ $email1, array( 'x-failed-recipients' =>
'[email protected]',
+ 'to' =>
'wiki-testwiki-2-ng0kgh-4upcj1ejt0ca3...@mediawiki-verp.wmflabs.org',
+ 'subject' => 'Mail delivery failed: returning
message to sender',
+ 'date' => 'Wed, 03 Dec 2014 16:00:19 +0000' )
+ ),
+ array(
+ $email2, array( 'to' =>
'[email protected]',
+ 'date' => 'Wed, 3 Dec 2014 15:30:52 -0800',
+ 'subject' => 'Delivery Status Notification
(Failure)',
+ 'status' => '5.5.0' )
+ ),
+ array(
+ $email3, array( 'to' =>
'wiki-testwiki-2-ng0kgh-4upcj1ejt0ca3...@mediawiki-verp.wmflabs.org',
+ 'date' => 'Wed, 03 Dec 2014 16:00:19 +0000',
+ 'subject' => 'Mail delivery failed: returning
message to sender',
+ 'smtp-code' => '550' )
+ )
+ );
+ }
+
/**
* @dataProvider provideBounceEmails
* @param $email
@@ -34,4 +61,16 @@
$this->assertArrayEquals( $regexResult, $plancakeResult );
}
+
+ /**
+ * @dataProvider provideBounceStatusEmails
+ * @param $emailStatus
+ * @param $expected
+ */
+ function testExtractHeadersWithStatus( $emailStatus, $expected ) {
+ $regexClass = new ProcessBounceWithRegex;
+ $regexResult = $regexClass->extractHeaders( $emailStatus );
+ $this->assertArrayEquals( $expected, $regexResult );
+ }
+
}
diff --git a/tests/bounce_emails/emailStatus1 b/tests/bounce_emails/emailStatus1
new file mode 100644
index 0000000..0c536fb
--- /dev/null
+++ b/tests/bounce_emails/emailStatus1
@@ -0,0 +1,52 @@
+From MAILER-DAEMON Wed Dec 03 16:00:19 2014
+Received: from Debian-exim by deployment-mx.eqiad.wmflabs with local (Exim
4.82)
+ id 1XwCLj-0004eu-R3
+ for
wiki-testwiki-2-ng0kgh-4upcj1ejt0ca3...@mediawiki-verp.wmflabs.org; Wed, 03 Dec
2014 16:00:19 +0000
+X-Failed-Recipients: [email protected]
+Auto-Submitted: auto-replied
+From: Mail Delivery System <[email protected]>
+To: wiki-testwiki-2-ng0kgh-4upcj1ejt0ca3...@mediawiki-verp.wmflabs.org
+Subject: Mail delivery failed: returning message to sender
+Message-Id: <[email protected]>
+Date: Wed, 03 Dec 2014 16:00:19 +0000
+
+This message was created automatically by mail delivery software.
+
+A message that you sent could not be delivered to one or more of its
+recipients. This is a permanent error. The following address(es) failed:
+
+ [email protected]
+ SMTP error from remote mail server after RCPT
TO:<[email protected]>:
+ host gmail-smtp-in.l.google.com [74.125.29.26]:
+ 550-5.1.1 The email account that you tried to reach does not exist. Please
try
+ 550-5.1.1 double-checking the recipient's email address for typos or
+ 550-5.1.1 unnecessary spaces. Learn more at
+ 550 5.1.1 http://support.google.com/mail/bin/answer.py?answer=6596
s52si24422382qge.11 - gsmtp
+
+------ This is a copy of the message, including all the headers. ------
+
+Return-path:
<wiki-testwiki-2-ng0kgh-4upcj1ejt0ca3...@mediawiki-verp.wmflabs.org>
+Received: from mediawiki-verp.eqiad.wmflabs ([10.68.17.11]:2307)
+ by deployment-mx.eqiad.wmflabs with esmtp (Exim 4.82)
+ (envelope-from
<wiki-testwiki-2-ng0kgh-4upcj1ejt0ca3...@mediawiki-verp.wmflabs.org>)
+ id 1XwCLj-0004eq-HB
+ for [email protected]; Wed, 03 Dec 2014 16:00:19 +0000
+Received: from www-data by mediawiki-verp.eqiad.wmflabs with local (Exim 4.82)
+ (envelope-from
<wiki-testwiki-2-ng0kgh-4upcj1ejt0ca3...@mediawiki-verp.wmflabs.org>)
+ id 1XwCLh-0006A8-Tw
+ for [email protected]; Wed, 03 Dec 2014 16:00:17 +0000
+To: Router123 <[email protected]>
+Subject: testwiki email from user "01tonythomas"
+X-PHP-Originating-Script: 0:UserMailer.php
+From: 01tonythomas <[email protected]>
+Date: Wed, 03 Dec 2014 16:00:17 +0000
+Message-ID: <[email protected]>
+X-Mailer: MediaWiki mailer
+MIME-Version: 1.0
+Content-type: text/plain; charset=UTF-8
+Content-transfer-encoding: 8bit
+
+Test bounce
+
+--
+This email was sent by 01tonythomas to Router123 by the "Email user" function
at testwiki.
\ No newline at end of file
diff --git a/tests/bounce_emails/emailStatus2 b/tests/bounce_emails/emailStatus2
new file mode 100644
index 0000000..7c99ff0
--- /dev/null
+++ b/tests/bounce_emails/emailStatus2
@@ -0,0 +1,70 @@
+Authentication-Results: hotmail.com; spf=none (sender IP is 65.55.90.45;
identity alignment result is pass and alignment mode is relaxed)
smtp.helo=SNT004-OMC1S34.hotmail.com; dkim=none (identity alignment result is
pass and alignment mode is relaxed) header.d=mail.hotmail.com; x-hmca=none
[email protected]
+X-SID-PRA: [email protected]
+X-Message-Delivery: Vj0xLjE7RD0wO0dEPTA7U0NMPTk7bD0xO3VzPTE=
+Received: from SNT004-OMC1S34.hotmail.com ([65.55.90.45]) by
BAY004-MC1F18.hotmail.com over TLS secured channel with Microsoft
SMTPSVC(7.5.7601.22751);
+ Wed, 3 Dec 2014 15:30:53 -0800
+From: [email protected]
+To: [email protected]
+Date: Wed, 3 Dec 2014 15:30:52 -0800
+MIME-Version: 1.0
+Content-Type: multipart/report; report-type=delivery-status;
+ boundary="9B095B5ADSN=_01D009F899E17AE900014FF9SNT004?OMC1S34.h"
+Message-ID: <[email protected]>
+Subject: Delivery Status Notification (Failure)
+Return-Path: <>
+X-OriginalArrivalTime: 03 Dec 2014 23:30:53.0101 (UTC)
FILETIME=[2DECDDD0:01D00F51]
+
+This is a MIME-formatted message.
+Portions of this message may be unreadable without a MIME-capable mail program.
+
+--9B095B5ADSN=_01D009F899E17AE900014FF9SNT004?OMC1S34.h
+Content-Type: text/plain; charset=unicode-1-1-utf-7
+
+This is an automatically generated Delivery Status Notification.
+
+Delivery to the following recipients failed.
+
+ [email protected]
+
+
+
+
+--9B095B5ADSN=_01D009F899E17AE900014FF9SNT004?OMC1S34.h
+Content-Type: message/delivery-status
+
+Reporting-MTA: dns;SNT004-OMC1S34.hotmail.com
+Received-From-MTA: dns;SNT148-W94
+Arrival-Date: Wed, 3 Dec 2014 15:30:52 -0800
+
+Final-Recipient: rfc822;[email protected]
+Action: failed
+Status: 5.5.0
+Diagnostic-Code: smtp;550 Requested action not taken: mailbox unavailable
+
+--9B095B5ADSN=_01D009F899E17AE900014FF9SNT004?OMC1S34.h
+Content-Type: message/rfc822
+
+Received: from SNT148-W94 ([65.55.90.7]) by SNT004-OMC1S34.hotmail.com over
TLS secured channel with Microsoft SMTPSVC(7.5.7601.22751);
+ Wed, 3 Dec 2014 15:30:52 -0800
+X-TMN: [wFdT/xYMAAje34hwFGRq8eJH5IQYpofwAN7z0l3/A8o=]
+X-Originating-Email: [[email protected]]
+Message-ID: <[email protected]>
+Return-Path: [email protected]
+Content-Type: multipart/alternative;
+ boundary="_9f0695af-6998-450a-a0b9-17e5c68c9e70_"
+From: [email protected]
+To: "[email protected]"
+ <[email protected]>
+Subject: Test email
+Date: Wed, 3 Dec 2014 23:30:51 +0000
+Importance: Normal
+MIME-Version: 1.0
+X-OriginalArrivalTime: 03 Dec 2014 23:30:52.0356 (UTC)
FILETIME=[2D7B3040:01D00F51]
+
+--_9f0695af-6998-450a-a0b9-17e5c68c9e70_
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: quoted-printable
+
+Hi
+
+--9B095B5ADSN=_01D009F899E17AE900014FF9SNT004?OMC1S34.h--
\ No newline at end of file
diff --git a/tests/bounce_emails/emailStatus3 b/tests/bounce_emails/emailStatus3
new file mode 100644
index 0000000..3a9c479
--- /dev/null
+++ b/tests/bounce_emails/emailStatus3
@@ -0,0 +1,51 @@
+From MAILER-DAEMON Wed Dec 03 16:00:19 2014
+Received: from Debian-exim by deployment-mx.eqiad.wmflabs with local (Exim
4.82)
+ id 1XwCLj-0004eu-R3
+ for
wiki-testwiki-2-ng0kgh-4upcj1ejt0ca3...@mediawiki-verp.wmflabs.org; Wed, 03 Dec
2014 16:00:19 +0000
+Auto-Submitted: auto-replied
+From: Mail Delivery System <[email protected]>
+To: wiki-testwiki-2-ng0kgh-4upcj1ejt0ca3...@mediawiki-verp.wmflabs.org
+Subject: Mail delivery failed: returning message to sender
+Message-Id: <[email protected]>
+Date: Wed, 03 Dec 2014 16:00:19 +0000
+
+This message was created automatically by mail delivery software.
+
+A message that you sent could not be delivered to one or more of its
+recipients. This is a permanent error. The following address(es) failed:
+
+ [email protected]
+ SMTP error from remote mail server after RCPT
TO:<[email protected]>:
+ host gmail-smtp-in.l.google.com [74.125.29.26]:
+ 550-5.1.1 The email account that you tried to reach does not exist. Please
try
+ 550-5.1.1 double-checking the recipient's email address for typos or
+ 550-5.1.1 unnecessary spaces. Learn more at
+ 550 5.1.1 http://support.google.com/mail/bin/answer.py?answer=6596
s52si24422382qge.11 - gsmtp
+
+------ This is a copy of the message, including all the headers. ------
+
+Return-path:
<wiki-testwiki-2-ng0kgh-4upcj1ejt0ca3...@mediawiki-verp.wmflabs.org>
+Received: from mediawiki-verp.eqiad.wmflabs ([10.68.17.11]:2307)
+ by deployment-mx.eqiad.wmflabs with esmtp (Exim 4.82)
+ (envelope-from
<wiki-testwiki-2-ng0kgh-4upcj1ejt0ca3...@mediawiki-verp.wmflabs.org>)
+ id 1XwCLj-0004eq-HB
+ for [email protected]; Wed, 03 Dec 2014 16:00:19 +0000
+Received: from www-data by mediawiki-verp.eqiad.wmflabs with local (Exim 4.82)
+ (envelope-from
<wiki-testwiki-2-ng0kgh-4upcj1ejt0ca3...@mediawiki-verp.wmflabs.org>)
+ id 1XwCLh-0006A8-Tw
+ for [email protected]; Wed, 03 Dec 2014 16:00:17 +0000
+To: Router123 <[email protected]>
+Subject: testwiki email from user "01tonythomas"
+X-PHP-Originating-Script: 0:UserMailer.php
+From: 01tonythomas <[email protected]>
+Date: Wed, 03 Dec 2014 16:00:17 +0000
+Message-ID: <[email protected]>
+X-Mailer: MediaWiki mailer
+MIME-Version: 1.0
+Content-type: text/plain; charset=UTF-8
+Content-transfer-encoding: 8bit
+
+Test bounce
+
+--
+This email was sent by 01tonythomas to Router123 by the "Email user" function
at testwiki.
\ No newline at end of file
--
To view, visit https://gerrit.wikimedia.org/r/177456
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Ice9d580ba81d7f3575a37267e97f33a9dafdcef5
Gerrit-PatchSet: 13
Gerrit-Project: mediawiki/extensions/BounceHandler
Gerrit-Branch: master
Gerrit-Owner: M4tx <[email protected]>
Gerrit-Reviewer: 01tonythomas <[email protected]>
Gerrit-Reviewer: Addshore <[email protected]>
Gerrit-Reviewer: Anomie <[email protected]>
Gerrit-Reviewer: CSteipp <[email protected]>
Gerrit-Reviewer: Hoo man <[email protected]>
Gerrit-Reviewer: Jgreen <[email protected]>
Gerrit-Reviewer: Kunalgrover05 <[email protected]>
Gerrit-Reviewer: Legoktm <[email protected]>
Gerrit-Reviewer: M4tx <[email protected]>
Gerrit-Reviewer: Reedy <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits