2013-05-14 10:57:41 -07:00
|
|
|
<?php
|
|
|
|
|
2015-06-15 18:02:26 +10:00
|
|
|
abstract class PhabricatorMailReceiver extends Phobject {
|
2013-05-14 10:57:41 -07:00
|
|
|
|
2015-01-28 11:13:29 -08:00
|
|
|
private $applicationEmail;
|
|
|
|
|
|
|
|
public function setApplicationEmail(
|
|
|
|
PhabricatorMetaMTAApplicationEmail $email) {
|
|
|
|
$this->applicationEmail = $email;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getApplicationEmail() {
|
|
|
|
return $this->applicationEmail;
|
|
|
|
}
|
|
|
|
|
2013-05-14 10:57:41 -07:00
|
|
|
abstract public function isEnabled();
|
|
|
|
abstract public function canAcceptMail(PhabricatorMetaMTAReceivedMail $mail);
|
2015-01-29 14:47:32 -08:00
|
|
|
final protected function canAcceptApplicationMail(
|
|
|
|
PhabricatorApplication $app,
|
|
|
|
PhabricatorMetaMTAReceivedMail $mail) {
|
|
|
|
|
|
|
|
$application_emails = id(new PhabricatorMetaMTAApplicationEmailQuery())
|
|
|
|
->setViewer($this->getViewer())
|
|
|
|
->withApplicationPHIDs(array($app->getPHID()))
|
|
|
|
->execute();
|
|
|
|
|
|
|
|
foreach ($mail->getToAddresses() as $to_address) {
|
|
|
|
foreach ($application_emails as $application_email) {
|
|
|
|
$create_address = $application_email->getAddress();
|
|
|
|
if ($this->matchAddresses($create_address, $to_address)) {
|
|
|
|
$this->setApplicationEmail($application_email);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2013-05-14 10:57:41 -07:00
|
|
|
|
2015-01-28 11:13:29 -08:00
|
|
|
|
2013-05-17 10:00:49 -07:00
|
|
|
abstract protected function processReceivedMail(
|
2013-05-17 03:51:57 -07:00
|
|
|
PhabricatorMetaMTAReceivedMail $mail,
|
2013-05-17 10:00:49 -07:00
|
|
|
PhabricatorUser $sender);
|
2013-05-17 03:51:57 -07:00
|
|
|
|
|
|
|
final public function receiveMail(
|
|
|
|
PhabricatorMetaMTAReceivedMail $mail,
|
|
|
|
PhabricatorUser $sender) {
|
|
|
|
$this->processReceivedMail($mail, $sender);
|
|
|
|
}
|
|
|
|
|
2015-01-19 16:07:26 -08:00
|
|
|
public function getViewer() {
|
|
|
|
return PhabricatorUser::getOmnipotentUser();
|
|
|
|
}
|
|
|
|
|
2013-05-17 03:49:29 -07:00
|
|
|
public function validateSender(
|
|
|
|
PhabricatorMetaMTAReceivedMail $mail,
|
|
|
|
PhabricatorUser $sender) {
|
|
|
|
|
When we fail to process mail, tell the user about it
Summary:
Ref T4371. Ref T4699. Fixes T3994.
Currently, we're very conservative about sending errors back to users. A concern I had about this was that mistakes could lead to email loops, massive amounts of email spam, etc. Because of this, I was pretty hesitant about replying to email with more email when I wrote this stuff.
However, this was a long time ago. We now have Message-ID deduplication, "X-Phabricator-Sent-This-Mail", generally better mail infrastructure, and rate limiting. Together, these mechanisms should reasonably prevent anything crazy (primarily, infinite email loops) from happening.
Thus:
- When we hit any processing error after receiving a mail, try to send the author a reply with details about what went wrong. These are limited to 6 per hour per address.
- Rewrite most of the errors to be more detailed and informative.
- Rewrite most of the errors in a user-facing voice ("You sent this mail..." instead of "This mail was sent..").
- Remove the redundant, less sophisticated code which does something similar in Differential.
Test Plan:
- Using `scripts/mail/mail_receiver.php`, artificially received a pile of mail.
- Hit a bunch of different errors.
- Saw reasonable error mail get sent to me.
- Saw other reasonable error mail get rate limited.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T3994, T4371, T4699
Differential Revision: https://secure.phabricator.com/D8692
2014-04-03 18:43:18 -07:00
|
|
|
$failure_reason = null;
|
|
|
|
if ($sender->getIsDisabled()) {
|
|
|
|
$failure_reason = pht(
|
|
|
|
'Your account (%s) is disabled, so you can not interact with '.
|
|
|
|
'Phabricator over email.',
|
|
|
|
$sender->getUsername());
|
|
|
|
} else if ($sender->getIsStandardUser()) {
|
|
|
|
if (!$sender->getIsApproved()) {
|
|
|
|
$failure_reason = pht(
|
|
|
|
'Your account (%s) has not been approved yet. You can not interact '.
|
|
|
|
'with Phabricator over email until your account is approved.',
|
|
|
|
$sender->getUsername());
|
|
|
|
} else if (PhabricatorUserEmail::isEmailVerificationRequired() &&
|
|
|
|
!$sender->getIsEmailVerified()) {
|
|
|
|
$failure_reason = pht(
|
|
|
|
'You have not verified the email address for your account (%s). '.
|
|
|
|
'You must verify your email address before you can interact '.
|
|
|
|
'with Phabricator over email.',
|
|
|
|
$sender->getUsername());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($failure_reason) {
|
2013-05-17 03:49:29 -07:00
|
|
|
throw new PhabricatorMetaMTAReceivedMailProcessingException(
|
|
|
|
MetaMTAReceivedMailStatus::STATUS_DISABLED_SENDER,
|
When we fail to process mail, tell the user about it
Summary:
Ref T4371. Ref T4699. Fixes T3994.
Currently, we're very conservative about sending errors back to users. A concern I had about this was that mistakes could lead to email loops, massive amounts of email spam, etc. Because of this, I was pretty hesitant about replying to email with more email when I wrote this stuff.
However, this was a long time ago. We now have Message-ID deduplication, "X-Phabricator-Sent-This-Mail", generally better mail infrastructure, and rate limiting. Together, these mechanisms should reasonably prevent anything crazy (primarily, infinite email loops) from happening.
Thus:
- When we hit any processing error after receiving a mail, try to send the author a reply with details about what went wrong. These are limited to 6 per hour per address.
- Rewrite most of the errors to be more detailed and informative.
- Rewrite most of the errors in a user-facing voice ("You sent this mail..." instead of "This mail was sent..").
- Remove the redundant, less sophisticated code which does something similar in Differential.
Test Plan:
- Using `scripts/mail/mail_receiver.php`, artificially received a pile of mail.
- Hit a bunch of different errors.
- Saw reasonable error mail get sent to me.
- Saw other reasonable error mail get rate limited.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T3994, T4371, T4699
Differential Revision: https://secure.phabricator.com/D8692
2014-04-03 18:43:18 -07:00
|
|
|
$failure_reason);
|
2013-05-17 03:49:29 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-15 08:44:54 -07:00
|
|
|
/**
|
|
|
|
* Identifies the sender's user account for a piece of received mail. Note
|
|
|
|
* that this method does not validate that the sender is who they say they
|
|
|
|
* are, just that they've presented some credential which corresponds to a
|
|
|
|
* recognizable user.
|
|
|
|
*/
|
|
|
|
public function loadSender(PhabricatorMetaMTAReceivedMail $mail) {
|
|
|
|
$raw_from = $mail->getHeader('From');
|
|
|
|
$from = self::getRawAddress($raw_from);
|
|
|
|
|
|
|
|
$reasons = array();
|
|
|
|
|
|
|
|
// Try to find a user with this email address.
|
|
|
|
$user = PhabricatorUser::loadOneWithEmailAddress($from);
|
|
|
|
if ($user) {
|
|
|
|
return $user;
|
|
|
|
} else {
|
|
|
|
$reasons[] = pht(
|
When we fail to process mail, tell the user about it
Summary:
Ref T4371. Ref T4699. Fixes T3994.
Currently, we're very conservative about sending errors back to users. A concern I had about this was that mistakes could lead to email loops, massive amounts of email spam, etc. Because of this, I was pretty hesitant about replying to email with more email when I wrote this stuff.
However, this was a long time ago. We now have Message-ID deduplication, "X-Phabricator-Sent-This-Mail", generally better mail infrastructure, and rate limiting. Together, these mechanisms should reasonably prevent anything crazy (primarily, infinite email loops) from happening.
Thus:
- When we hit any processing error after receiving a mail, try to send the author a reply with details about what went wrong. These are limited to 6 per hour per address.
- Rewrite most of the errors to be more detailed and informative.
- Rewrite most of the errors in a user-facing voice ("You sent this mail..." instead of "This mail was sent..").
- Remove the redundant, less sophisticated code which does something similar in Differential.
Test Plan:
- Using `scripts/mail/mail_receiver.php`, artificially received a pile of mail.
- Hit a bunch of different errors.
- Saw reasonable error mail get sent to me.
- Saw other reasonable error mail get rate limited.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T3994, T4371, T4699
Differential Revision: https://secure.phabricator.com/D8692
2014-04-03 18:43:18 -07:00
|
|
|
'This email was sent from "%s", but that address is not recognized by '.
|
|
|
|
'Phabricator and does not correspond to any known user account.',
|
2013-05-15 08:44:54 -07:00
|
|
|
$raw_from);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we missed on "From", try "Reply-To" if we're configured for it.
|
When we fail to process mail, tell the user about it
Summary:
Ref T4371. Ref T4699. Fixes T3994.
Currently, we're very conservative about sending errors back to users. A concern I had about this was that mistakes could lead to email loops, massive amounts of email spam, etc. Because of this, I was pretty hesitant about replying to email with more email when I wrote this stuff.
However, this was a long time ago. We now have Message-ID deduplication, "X-Phabricator-Sent-This-Mail", generally better mail infrastructure, and rate limiting. Together, these mechanisms should reasonably prevent anything crazy (primarily, infinite email loops) from happening.
Thus:
- When we hit any processing error after receiving a mail, try to send the author a reply with details about what went wrong. These are limited to 6 per hour per address.
- Rewrite most of the errors to be more detailed and informative.
- Rewrite most of the errors in a user-facing voice ("You sent this mail..." instead of "This mail was sent..").
- Remove the redundant, less sophisticated code which does something similar in Differential.
Test Plan:
- Using `scripts/mail/mail_receiver.php`, artificially received a pile of mail.
- Hit a bunch of different errors.
- Saw reasonable error mail get sent to me.
- Saw other reasonable error mail get rate limited.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T3994, T4371, T4699
Differential Revision: https://secure.phabricator.com/D8692
2014-04-03 18:43:18 -07:00
|
|
|
$raw_reply_to = $mail->getHeader('Reply-To');
|
|
|
|
if (strlen($raw_reply_to)) {
|
|
|
|
$reply_to_key = 'metamta.insecure-auth-with-reply-to';
|
|
|
|
$allow_reply_to = PhabricatorEnv::getEnvConfig($reply_to_key);
|
|
|
|
if ($allow_reply_to) {
|
|
|
|
$reply_to = self::getRawAddress($raw_reply_to);
|
|
|
|
|
|
|
|
$user = PhabricatorUser::loadOneWithEmailAddress($reply_to);
|
|
|
|
if ($user) {
|
|
|
|
return $user;
|
|
|
|
} else {
|
|
|
|
$reasons[] = pht(
|
|
|
|
'Phabricator is configured to authenticate users using the '.
|
|
|
|
'"Reply-To" header, but the reply address ("%s") on this '.
|
|
|
|
'message does not correspond to any known user account.',
|
|
|
|
$raw_reply_to);
|
|
|
|
}
|
2013-05-15 08:44:54 -07:00
|
|
|
} else {
|
|
|
|
$reasons[] = pht(
|
When we fail to process mail, tell the user about it
Summary:
Ref T4371. Ref T4699. Fixes T3994.
Currently, we're very conservative about sending errors back to users. A concern I had about this was that mistakes could lead to email loops, massive amounts of email spam, etc. Because of this, I was pretty hesitant about replying to email with more email when I wrote this stuff.
However, this was a long time ago. We now have Message-ID deduplication, "X-Phabricator-Sent-This-Mail", generally better mail infrastructure, and rate limiting. Together, these mechanisms should reasonably prevent anything crazy (primarily, infinite email loops) from happening.
Thus:
- When we hit any processing error after receiving a mail, try to send the author a reply with details about what went wrong. These are limited to 6 per hour per address.
- Rewrite most of the errors to be more detailed and informative.
- Rewrite most of the errors in a user-facing voice ("You sent this mail..." instead of "This mail was sent..").
- Remove the redundant, less sophisticated code which does something similar in Differential.
Test Plan:
- Using `scripts/mail/mail_receiver.php`, artificially received a pile of mail.
- Hit a bunch of different errors.
- Saw reasonable error mail get sent to me.
- Saw other reasonable error mail get rate limited.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T3994, T4371, T4699
Differential Revision: https://secure.phabricator.com/D8692
2014-04-03 18:43:18 -07:00
|
|
|
'(Phabricator is not configured to authenticate users using the '.
|
|
|
|
'"Reply-To" header, so it was ignored.)');
|
2013-05-15 08:44:54 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we don't know who this user is, load or create an external user
|
|
|
|
// account for them if we're configured for it.
|
|
|
|
$email_key = 'phabricator.allow-email-users';
|
|
|
|
$allow_email_users = PhabricatorEnv::getEnvConfig($email_key);
|
|
|
|
if ($allow_email_users) {
|
2014-01-14 17:17:18 -08:00
|
|
|
$from_obj = new PhutilEmailAddress($from);
|
|
|
|
$xuser = id(new PhabricatorExternalAccountQuery())
|
2015-01-19 16:07:26 -08:00
|
|
|
->setViewer($this->getViewer())
|
2014-01-14 17:17:18 -08:00
|
|
|
->withAccountTypes(array('email'))
|
|
|
|
->withAccountDomains(array($from_obj->getDomainName(), 'self'))
|
|
|
|
->withAccountIDs(array($from_obj->getAddress()))
|
Introduce CAN_EDIT for ExternalAccount, and make CAN_VIEW more liberal
Summary:
Fixes T3732. Ref T1205. Ref T3116.
External accounts (like emails used as identities, Facebook accounts, LDAP accounts, etc.) are stored in "ExternalAccount" objects.
Currently, we have a very restrictive `CAN_VIEW` policy for ExternalAccounts, to add an extra layer of protection to make sure users can't use them in unintended ways. For example, it would be bad if a user could link their Phabricator account to a Facebook account without proper authentication. All of the controllers which do sensitive things have checks anyway, but a restrictive CAN_VIEW provided an extra layer of protection. Se T3116 for some discussion.
However, this means that when grey/external users take actions (via email, or via applications like Legalpad) other users can't load the account handles and can't see anything about the actor (they just see "Restricted External Account" or similar).
Balancing these concerns is mostly about not making a huge mess while doing it. This seems like a reasonable approach:
- Add `CAN_EDIT` on these objects.
- Make that very restricted, but open up `CAN_VIEW`.
- Require `CAN_EDIT` any time we're going to do something authentication/identity related.
This is slightly easier to get wrong (forget CAN_EDIT) than other approaches, but pretty simple, and we always have extra checks in place anyway -- this is just a safety net.
I'm not quite sure how we should identify external accounts, so for now we're just rendering "Email User" or similar -- clearly not a bug, but not identifying. We can figure out what to render in the long term elsewhere.
Test Plan:
- Viewed external accounts.
- Linked an external account.
- Refreshed an external account.
- Edited profile picture.
- Viewed sessions panel.
- Published a bunch of stuff to Asana/JIRA.
- Legalpad signature page now shows external accounts.
{F171595}
Reviewers: chad, btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T3732, T1205, T3116
Differential Revision: https://secure.phabricator.com/D9767
2014-07-10 10:18:10 -07:00
|
|
|
->requireCapabilities(
|
|
|
|
array(
|
|
|
|
PhabricatorPolicyCapability::CAN_VIEW,
|
|
|
|
PhabricatorPolicyCapability::CAN_EDIT,
|
|
|
|
))
|
2014-01-14 17:17:18 -08:00
|
|
|
->loadOneOrCreate();
|
2013-05-15 08:44:54 -07:00
|
|
|
return $xuser->getPhabricatorUser();
|
|
|
|
} else {
|
Never send normal mail to unverified addresses
Summary:
Ref T12237. This tightens our delivery rules, which previously sent normal mail to unverified addresses:
- We sent general mail to unverified addresses so that you wouldn't miss anything between the time you sign up (or have an account created) and the time you verify your address. This was imagined as a slight convenience for users.
- We sent automatic reply mail to unverified addresses if they sent mail to us first, saying "we don't recognize that address". This was imagined as a convenience for users who accidentally send mail "From" the wrong address (personal vs work, for example).
I think both behaviors are probably a little better for users on the balance, but not having mail providers randomly shut us off without warning is better for me, personally -- so stop doing this stuff.
This creates a problem which we likely need to solve before the release is cut:
- On installs which do not require mail verification, mail to you will now mostly-silently be dropped if you never bothered to verify your address.
I'd like to solve this by adding some kind of per-user alert that says "We recently tried to send you some mail but you haven't verified your address.", and giving them links to verify the address and review the mail. I'll pursue this after restoring mail service to `secure.phabricator.com`.
Test Plan:
- Added a unit test.
- Unverified my address, sent mail, saw it get dropped.
- Reverified my address, sent mail, saw it go through.
- Verified that important mail (password reset, invite, confirm-this-address) either uses "Force Delivery" (skips this check) or "Raw To Addresses" (also skips this check).
- Verified that Phacility instance stuff is also covered: it uses the same invite flow.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T12237
Differential Revision: https://secure.phabricator.com/D17329
2017-02-09 08:35:16 -08:00
|
|
|
// NOTE: Currently, we'll always drop this mail (since it's headed to
|
|
|
|
// an unverified recipient). See T12237. These details are still useful
|
|
|
|
// because they'll appear in the mail logs and Mail web UI.
|
|
|
|
|
2013-05-15 08:44:54 -07:00
|
|
|
$reasons[] = pht(
|
When we fail to process mail, tell the user about it
Summary:
Ref T4371. Ref T4699. Fixes T3994.
Currently, we're very conservative about sending errors back to users. A concern I had about this was that mistakes could lead to email loops, massive amounts of email spam, etc. Because of this, I was pretty hesitant about replying to email with more email when I wrote this stuff.
However, this was a long time ago. We now have Message-ID deduplication, "X-Phabricator-Sent-This-Mail", generally better mail infrastructure, and rate limiting. Together, these mechanisms should reasonably prevent anything crazy (primarily, infinite email loops) from happening.
Thus:
- When we hit any processing error after receiving a mail, try to send the author a reply with details about what went wrong. These are limited to 6 per hour per address.
- Rewrite most of the errors to be more detailed and informative.
- Rewrite most of the errors in a user-facing voice ("You sent this mail..." instead of "This mail was sent..").
- Remove the redundant, less sophisticated code which does something similar in Differential.
Test Plan:
- Using `scripts/mail/mail_receiver.php`, artificially received a pile of mail.
- Hit a bunch of different errors.
- Saw reasonable error mail get sent to me.
- Saw other reasonable error mail get rate limited.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T3994, T4371, T4699
Differential Revision: https://secure.phabricator.com/D8692
2014-04-03 18:43:18 -07:00
|
|
|
'Phabricator is also not configured to allow unknown external users '.
|
|
|
|
'to send mail to the system using just an email address.');
|
|
|
|
$reasons[] = pht(
|
|
|
|
'To interact with Phabricator, add this address ("%s") to your '.
|
|
|
|
'account.',
|
|
|
|
$raw_from);
|
2013-05-15 08:44:54 -07:00
|
|
|
}
|
|
|
|
|
2015-01-28 11:13:29 -08:00
|
|
|
if ($this->getApplicationEmail()) {
|
|
|
|
$application_email = $this->getApplicationEmail();
|
|
|
|
$default_user_phid = $application_email->getConfigValue(
|
|
|
|
PhabricatorMetaMTAApplicationEmail::CONFIG_DEFAULT_AUTHOR);
|
|
|
|
|
|
|
|
if ($default_user_phid) {
|
|
|
|
$user = id(new PhabricatorUser())->loadOneWhere(
|
|
|
|
'phid = %s',
|
|
|
|
$default_user_phid);
|
|
|
|
if ($user) {
|
|
|
|
return $user;
|
|
|
|
}
|
|
|
|
|
Never send normal mail to unverified addresses
Summary:
Ref T12237. This tightens our delivery rules, which previously sent normal mail to unverified addresses:
- We sent general mail to unverified addresses so that you wouldn't miss anything between the time you sign up (or have an account created) and the time you verify your address. This was imagined as a slight convenience for users.
- We sent automatic reply mail to unverified addresses if they sent mail to us first, saying "we don't recognize that address". This was imagined as a convenience for users who accidentally send mail "From" the wrong address (personal vs work, for example).
I think both behaviors are probably a little better for users on the balance, but not having mail providers randomly shut us off without warning is better for me, personally -- so stop doing this stuff.
This creates a problem which we likely need to solve before the release is cut:
- On installs which do not require mail verification, mail to you will now mostly-silently be dropped if you never bothered to verify your address.
I'd like to solve this by adding some kind of per-user alert that says "We recently tried to send you some mail but you haven't verified your address.", and giving them links to verify the address and review the mail. I'll pursue this after restoring mail service to `secure.phabricator.com`.
Test Plan:
- Added a unit test.
- Unverified my address, sent mail, saw it get dropped.
- Reverified my address, sent mail, saw it go through.
- Verified that important mail (password reset, invite, confirm-this-address) either uses "Force Delivery" (skips this check) or "Raw To Addresses" (also skips this check).
- Verified that Phacility instance stuff is also covered: it uses the same invite flow.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T12237
Differential Revision: https://secure.phabricator.com/D17329
2017-02-09 08:35:16 -08:00
|
|
|
$reasons[] = pht(
|
|
|
|
'Phabricator is misconfigured: the application email '.
|
|
|
|
'"%s" is set to user "%s", but that user does not exist.',
|
|
|
|
$application_email->getAddress(),
|
|
|
|
$default_user_phid);
|
|
|
|
}
|
2015-01-28 11:13:29 -08:00
|
|
|
}
|
|
|
|
|
When we fail to process mail, tell the user about it
Summary:
Ref T4371. Ref T4699. Fixes T3994.
Currently, we're very conservative about sending errors back to users. A concern I had about this was that mistakes could lead to email loops, massive amounts of email spam, etc. Because of this, I was pretty hesitant about replying to email with more email when I wrote this stuff.
However, this was a long time ago. We now have Message-ID deduplication, "X-Phabricator-Sent-This-Mail", generally better mail infrastructure, and rate limiting. Together, these mechanisms should reasonably prevent anything crazy (primarily, infinite email loops) from happening.
Thus:
- When we hit any processing error after receiving a mail, try to send the author a reply with details about what went wrong. These are limited to 6 per hour per address.
- Rewrite most of the errors to be more detailed and informative.
- Rewrite most of the errors in a user-facing voice ("You sent this mail..." instead of "This mail was sent..").
- Remove the redundant, less sophisticated code which does something similar in Differential.
Test Plan:
- Using `scripts/mail/mail_receiver.php`, artificially received a pile of mail.
- Hit a bunch of different errors.
- Saw reasonable error mail get sent to me.
- Saw other reasonable error mail get rate limited.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T3994, T4371, T4699
Differential Revision: https://secure.phabricator.com/D8692
2014-04-03 18:43:18 -07:00
|
|
|
$reasons = implode("\n\n", $reasons);
|
|
|
|
|
2013-05-15 08:44:54 -07:00
|
|
|
throw new PhabricatorMetaMTAReceivedMailProcessingException(
|
|
|
|
MetaMTAReceivedMailStatus::STATUS_UNKNOWN_SENDER,
|
When we fail to process mail, tell the user about it
Summary:
Ref T4371. Ref T4699. Fixes T3994.
Currently, we're very conservative about sending errors back to users. A concern I had about this was that mistakes could lead to email loops, massive amounts of email spam, etc. Because of this, I was pretty hesitant about replying to email with more email when I wrote this stuff.
However, this was a long time ago. We now have Message-ID deduplication, "X-Phabricator-Sent-This-Mail", generally better mail infrastructure, and rate limiting. Together, these mechanisms should reasonably prevent anything crazy (primarily, infinite email loops) from happening.
Thus:
- When we hit any processing error after receiving a mail, try to send the author a reply with details about what went wrong. These are limited to 6 per hour per address.
- Rewrite most of the errors to be more detailed and informative.
- Rewrite most of the errors in a user-facing voice ("You sent this mail..." instead of "This mail was sent..").
- Remove the redundant, less sophisticated code which does something similar in Differential.
Test Plan:
- Using `scripts/mail/mail_receiver.php`, artificially received a pile of mail.
- Hit a bunch of different errors.
- Saw reasonable error mail get sent to me.
- Saw other reasonable error mail get rate limited.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T3994, T4371, T4699
Differential Revision: https://secure.phabricator.com/D8692
2014-04-03 18:43:18 -07:00
|
|
|
$reasons);
|
2013-05-15 08:44:54 -07:00
|
|
|
}
|
|
|
|
|
2013-05-14 10:57:41 -07:00
|
|
|
/**
|
|
|
|
* Determine if two inbound email addresses are effectively identical. This
|
|
|
|
* method strips and normalizes addresses so that equivalent variations are
|
|
|
|
* correctly detected as identical. For example, these addresses are all
|
|
|
|
* considered to match one another:
|
|
|
|
*
|
|
|
|
* "Abraham Lincoln" <alincoln@example.com>
|
|
|
|
* alincoln@example.com
|
|
|
|
* <ALincoln@example.com>
|
|
|
|
* "Abraham" <phabricator+ALINCOLN@EXAMPLE.COM> # With configured prefix.
|
|
|
|
*
|
|
|
|
* @param string Email address.
|
|
|
|
* @param string Another email address.
|
|
|
|
* @return bool True if addresses match.
|
|
|
|
*/
|
|
|
|
public static function matchAddresses($u, $v) {
|
2013-05-15 08:44:54 -07:00
|
|
|
$u = self::getRawAddress($u);
|
|
|
|
$v = self::getRawAddress($v);
|
2013-05-14 10:57:41 -07:00
|
|
|
|
|
|
|
$u = self::stripMailboxPrefix($u);
|
|
|
|
$v = self::stripMailboxPrefix($v);
|
|
|
|
|
|
|
|
return ($u === $v);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Strip a global mailbox prefix from an address if it is present. Phabricator
|
|
|
|
* can be configured to prepend a prefix to all reply addresses, which can
|
|
|
|
* make forwarding rules easier to write. A prefix looks like:
|
|
|
|
*
|
|
|
|
* example@phabricator.example.com # No Prefix
|
|
|
|
* phabricator+example@phabricator.example.com # Prefix "phabricator"
|
|
|
|
*
|
|
|
|
* @param string Email address, possibly with a mailbox prefix.
|
|
|
|
* @return string Email address with any prefix stripped.
|
|
|
|
*/
|
|
|
|
public static function stripMailboxPrefix($address) {
|
|
|
|
$address = id(new PhutilEmailAddress($address))->getAddress();
|
|
|
|
|
|
|
|
$prefix_key = 'metamta.single-reply-handler-prefix';
|
|
|
|
$prefix = PhabricatorEnv::getEnvConfig($prefix_key);
|
|
|
|
|
|
|
|
$len = strlen($prefix);
|
|
|
|
|
|
|
|
if ($len) {
|
|
|
|
$prefix = $prefix.'+';
|
|
|
|
$len = $len + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($len) {
|
|
|
|
if (!strncasecmp($address, $prefix, $len)) {
|
|
|
|
$address = substr($address, strlen($prefix));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $address;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-15 08:44:54 -07:00
|
|
|
/**
|
|
|
|
* Reduce an email address to its canonical form. For example, an adddress
|
|
|
|
* like:
|
|
|
|
*
|
|
|
|
* "Abraham Lincoln" < ALincoln@example.com >
|
|
|
|
*
|
|
|
|
* ...will be reduced to:
|
|
|
|
*
|
|
|
|
* alincoln@example.com
|
|
|
|
*
|
|
|
|
* @param string Email address in noncanonical form.
|
|
|
|
* @return string Canonical email address.
|
|
|
|
*/
|
|
|
|
public static function getRawAddress($address) {
|
|
|
|
$address = id(new PhutilEmailAddress($address))->getAddress();
|
|
|
|
return trim(phutil_utf8_strtolower($address));
|
|
|
|
}
|
|
|
|
|
2013-05-14 10:57:41 -07:00
|
|
|
}
|