diff --git a/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php b/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php --- a/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php +++ b/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php @@ -380,6 +380,11 @@ 'Resource deflation is now managed automatically.'), 'celerity.minify' => pht( 'Resource minificatino is now managed automatically.'), + + 'metamta.domain' => pht( + 'Mail thread IDs are now generated automatically.'), + 'metamta.placeholder-to-recipient' => pht( + 'Placeholder recipients are now generated automatically.'), ); return $ancient_config; diff --git a/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php b/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php --- a/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php +++ b/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php @@ -139,13 +139,6 @@ great. A number of other mailers are available (e.g., SES, SendGrid, SMTP, custom mailers). This option is deprecated in favor of 'cluster.mailers'. EODOC -)); - - $placeholder_description = $this->deformat(pht(<<deformat(pht(<<setDescription(pht('Default "From" address.')), - $this->newOption( - 'metamta.domain', - 'string', - 'phabricator.example.com') - ->setDescription(pht('Domain used to generate Message-IDs.')), $this->newOption( 'metamta.one-mail-per-recipient', 'bool', @@ -265,9 +253,6 @@ )) ->setSummary(pht('Trust "Reply-To" headers for authentication.')) ->setDescription($reply_to_description), - $this->newOption('metamta.placeholder-to-recipient', 'string', null) - ->setSummary(pht('Placeholder for mail with only CCs.')) - ->setDescription($placeholder_description), $this->newOption('metamta.public-replies', 'bool', false) ->setBoolOptions( array( diff --git a/src/applications/metamta/constants/MetaMTAReceivedMailStatus.php b/src/applications/metamta/constants/MetaMTAReceivedMailStatus.php --- a/src/applications/metamta/constants/MetaMTAReceivedMailStatus.php +++ b/src/applications/metamta/constants/MetaMTAReceivedMailStatus.php @@ -17,6 +17,7 @@ const STATUS_UNHANDLED_EXCEPTION = 'err:exception'; const STATUS_EMPTY = 'err:empty'; const STATUS_EMPTY_IGNORED = 'err:empty-ignored'; + const STATUS_VOID_RECIPIENT = 'err:void'; public static function getHumanReadableName($status) { $map = array( @@ -34,6 +35,7 @@ self::STATUS_UNHANDLED_EXCEPTION => pht('Unhandled Exception'), self::STATUS_EMPTY => pht('Empty Mail'), self::STATUS_EMPTY_IGNORED => pht('Ignored Empty Mail'), + self::STATUS_VOID_RECIPIENT => pht('Void Recipient'), ); return idx($map, $status, pht('Processing Exception')); diff --git a/src/applications/metamta/storage/PhabricatorMetaMTAMail.php b/src/applications/metamta/storage/PhabricatorMetaMTAMail.php --- a/src/applications/metamta/storage/PhabricatorMetaMTAMail.php +++ b/src/applications/metamta/storage/PhabricatorMetaMTAMail.php @@ -857,7 +857,7 @@ // aren't in the form ""; this is also required // by RFC 2822, although some clients are more liberal in what they // accept. - $domain = PhabricatorEnv::getEnvConfig('metamta.domain'); + $domain = $this->newMailDomain(); $value = '<'.$value.'@'.$domain.'>'; if ($is_first && $mailer->supportsMessageIDHeader()) { @@ -1017,18 +1017,13 @@ return null; } - // Some mailers require a valid "To:" in order to deliver mail. If we - // don't have any "To:", try to fill it in with a placeholder "To:". - // If that also fails, move the "Cc:" line to "To:". + // Some mailers require a valid "To:" in order to deliver mail. If we don't + // have any "To:", fill it in with a placeholder "To:". This allows client + // rules based on whether the recipient is in "To:" or "CC:" to continue + // behaving in the same way. if (!$add_to) { - $placeholder_key = 'metamta.placeholder-to-recipient'; - $placeholder = PhabricatorEnv::getEnvConfig($placeholder_key); - if ($placeholder !== null) { - $add_to = array($placeholder); - } else { - $add_to = $add_cc; - $add_cc = array(); - } + $void_recipient = $this->newVoidEmailAddress(); + $add_to = array($void_recipient->getAddress()); } $add_to = array_unique($add_to); @@ -1467,6 +1462,19 @@ return '/mail/detail/'.$this->getID().'/'; } + private function newMailDomain() { + $install_uri = PhabricatorEnv::getURI('/'); + $install_uri = new PhutilURI($install_uri); + + return $install_uri->getDomain(); + } + + public function newVoidEmailAddress() { + $domain = $this->newMailDomain(); + $address = "void-recipient@{$domain}"; + return new PhutilEmailAddress($address); + } + /* -( Routing )------------------------------------------------------------ */ diff --git a/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php b/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php --- a/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php +++ b/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php @@ -109,6 +109,7 @@ try { $this->dropMailFromPhabricator(); $this->dropMailAlreadyReceived(); + $this->dropMailToVoidRecipient(); $receiver = $this->loadReceiver(); $sender = $receiver->loadSender($this); @@ -260,6 +261,36 @@ $message); } + private function dropMailToVoidRecipient() { + $void_address = id(new PhabricatorMetaMTAMail()) + ->newVoidEmailAddress(); + + $void_recipient = null; + foreach ($this->getToAddresses() as $raw_address) { + try { + $address = new PhutilEmailAddress($raw_address); + } catch (Exception $ex) { + continue; + } + + if ($address->getAddress() == $void_address->getAddress()) { + $void_recipient = $address; + break; + } + } + + if (!$void_recipient) { + return; + } + + throw new PhabricatorMetaMTAReceivedMailProcessingException( + MetaMTAReceivedMailStatus::STATUS_VOID_RECIPIENT, + pht( + 'Ignoring email to void recipient ("%s"). This is a placeholder '. + 'recipient Phabricator generates when a message only has "CC" '. + 'addresses.', + $void_recipient->getAddress())); + } /** * Load a concrete instance of the @{class:PhabricatorMailReceiver} which diff --git a/src/docs/user/configuration/configuring_outbound_email.diviner b/src/docs/user/configuration/configuring_outbound_email.diviner --- a/src/docs/user/configuration/configuring_outbound_email.diviner +++ b/src/docs/user/configuration/configuring_outbound_email.diviner @@ -45,7 +45,6 @@ - **metamta.default-address** determines where mail is sent "From" by default. If your domain is `example.org`, set this to something like `noreply@example.org`. - - **metamta.domain** should be set to your domain, e.g. `example.org`. - **metamta.can-send-as-user** should be left as `false` in most cases, but see the documentation for details.