Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/metamta/adapter/PhabricatorMailImplementationPostmarkAdapter.php b/src/applications/metamta/adapter/PhabricatorMailImplementationPostmarkAdapter.php
index bd5ee820af..5792ba08f8 100644
--- a/src/applications/metamta/adapter/PhabricatorMailImplementationPostmarkAdapter.php
+++ b/src/applications/metamta/adapter/PhabricatorMailImplementationPostmarkAdapter.php
@@ -1,112 +1,124 @@
<?php
final class PhabricatorMailImplementationPostmarkAdapter
extends PhabricatorMailImplementationAdapter {
const ADAPTERTYPE = 'postmark';
private $parameters = array();
public function setFrom($email, $name = '') {
$this->parameters['From'] = $this->renderAddress($email, $name);
return $this;
}
public function addReplyTo($email, $name = '') {
$this->parameters['ReplyTo'] = $this->renderAddress($email, $name);
return $this;
}
public function addTos(array $emails) {
foreach ($emails as $email) {
$this->parameters['To'][] = $email;
}
return $this;
}
public function addCCs(array $emails) {
foreach ($emails as $email) {
$this->parameters['Cc'][] = $email;
}
return $this;
}
public function addAttachment($data, $filename, $mimetype) {
$this->parameters['Attachments'][] = array(
'Name' => $filename,
'ContentType' => $mimetype,
'Content' => base64_encode($data),
);
return $this;
}
public function addHeader($header_name, $header_value) {
$this->parameters['Headers'][] = array(
'Name' => $header_name,
'Value' => $header_value,
);
return $this;
}
public function setBody($body) {
$this->parameters['TextBody'] = $body;
return $this;
}
public function setHTMLBody($html_body) {
$this->parameters['HtmlBody'] = $html_body;
return $this;
}
public function setSubject($subject) {
$this->parameters['Subject'] = $subject;
return $this;
}
public function supportsMessageIDHeader() {
return true;
}
protected function validateOptions(array $options) {
PhutilTypeSpec::checkMap(
$options,
array(
'access-token' => 'string',
+ 'inbound-addresses' => 'list<string>',
));
+
+ // Make sure this is properly formatted.
+ PhutilCIDRList::newList($options['inbound-addresses']);
}
public function newDefaultOptions() {
return array(
'access-token' => null,
+ 'inbound-addresses' => array(
+ // Via Postmark support circa February 2018, see:
+ //
+ // https://postmarkapp.com/support/article/800-ips-for-firewalls
+ //
+ // "Configuring Outbound Email" should be updated if this changes.
+ '50.31.156.6/32',
+ ),
);
}
public function newLegacyOptions() {
return array();
}
public function send() {
$access_token = $this->getOption('access-token');
$parameters = $this->parameters;
$flatten = array(
'To',
'Cc',
);
foreach ($flatten as $key) {
if (isset($parameters[$key])) {
$parameters[$key] = implode(', ', $parameters[$key]);
}
}
id(new PhutilPostmarkFuture())
->setAccessToken($access_token)
->setMethod('email', $parameters)
->resolve();
return true;
}
}
diff --git a/src/applications/metamta/controller/PhabricatorMetaMTAPostmarkReceiveController.php b/src/applications/metamta/controller/PhabricatorMetaMTAPostmarkReceiveController.php
index a54da6fb40..345cd93fe1 100644
--- a/src/applications/metamta/controller/PhabricatorMetaMTAPostmarkReceiveController.php
+++ b/src/applications/metamta/controller/PhabricatorMetaMTAPostmarkReceiveController.php
@@ -1,87 +1,102 @@
<?php
final class PhabricatorMetaMTAPostmarkReceiveController
extends PhabricatorMetaMTAController {
public function shouldRequireLogin() {
return false;
}
/**
* @phutil-external-symbol class PhabricatorStartup
*/
public function handleRequest(AphrontRequest $request) {
// Don't process requests if we don't have a configured Postmark adapter.
$mailers = PhabricatorMetaMTAMail::newMailersWithTypes(
array(
PhabricatorMailImplementationPostmarkAdapter::ADAPTERTYPE,
));
if (!$mailers) {
return new Aphront404Response();
}
+ $remote_address = $request->getRemoteAddress();
+ $any_remote_match = false;
+ foreach ($mailers as $mailer) {
+ $inbound_addresses = $mailer->getOption('inbound-addresses');
+ $cidr_list = PhutilCIDRList::newList($inbound_addresses);
+ if ($cidr_list->containsAddress($remote_address)) {
+ $any_remote_match = true;
+ break;
+ }
+ }
+
+ if (!$any_remote_match) {
+ return new Aphront400Response();
+ }
+
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$raw_input = PhabricatorStartup::getRawInput();
try {
$data = phutil_json_decode($raw_input);
} catch (Exception $ex) {
return new Aphront400Response();
}
$raw_headers = array();
$header_items = idx($data, 'Headers', array());
foreach ($header_items as $header_item) {
$name = idx($header_item, 'Name');
$value = idx($header_item, 'Value');
$raw_headers[$name] = $value;
}
$headers = array(
'to' => idx($data, 'To'),
'from' => idx($data, 'From'),
'cc' => idx($data, 'Cc'),
'subject' => idx($data, 'Subject'),
) + $raw_headers;
$received = id(new PhabricatorMetaMTAReceivedMail())
->setHeaders($headers)
->setBodies(
array(
'text' => idx($data, 'TextBody'),
'html' => idx($data, 'HtmlBody'),
));
$file_phids = array();
$attachments = idx($data, 'Attachments', array());
foreach ($attachments as $attachment) {
$file_data = idx($attachment, 'Content');
$file_data = base64_decode($file_data);
try {
$file = PhabricatorFile::newFromFileData(
$file_data,
array(
'name' => idx($attachment, 'Name'),
'viewPolicy' => PhabricatorPolicies::POLICY_NOONE,
));
$file_phids[] = $file->getPHID();
} catch (Exception $ex) {
phlog($ex);
}
}
$received->setAttachments($file_phids);
try {
$received->save();
$received->processReceivedMail();
} catch (Exception $ex) {
phlog($ex);
}
return id(new AphrontWebpageResponse())
->setContent(pht("Got it! Thanks, Postmark!\n"));
}
}
diff --git a/src/docs/user/configuration/configuring_inbound_email.diviner b/src/docs/user/configuration/configuring_inbound_email.diviner
index ada4ddb828..f4f367d57e 100644
--- a/src/docs/user/configuration/configuring_inbound_email.diviner
+++ b/src/docs/user/configuration/configuring_inbound_email.diviner
@@ -1,230 +1,234 @@
@title Configuring Inbound Email
@group config
This document contains instructions for configuring inbound email, so users
may interact with some Phabricator applications via email.
= Preamble =
This can be extremely difficult to configure correctly. This is doubly true if
you use a local MTA.
There are a few approaches available:
| Receive Mail With | Setup | Cost | Notes |
|--------|-------|------|-------|
| Mailgun | Easy | Cheap | Recommended |
| Postmark | Easy | Cheap | Recommended |
| SendGrid | Easy | Cheap | |
| Local MTA | Extremely Difficult | Free | Strongly discouraged! |
The remainder of this document walks through configuring Phabricator to
receive mail, and then configuring your chosen transport to deliver mail
to Phabricator.
= Configuring Phabricator =
By default, Phabricator uses a `noreply@phabricator.example.com` email address
as the 'From' (configurable with `metamta.default-address`) and sets
'Reply-To' to the user generating the email (e.g., by making a comment), if the
mail was generated by a user action. This means that users can reply (or
reply-all) to email to discuss changes, but the conversation won't be recorded
in Phabricator and users will not be able to take actions like claiming tasks or
requesting changes to revisions.
To change this behavior so that users can interact with objects in Phabricator
over email, change the configuration key `metamta.reply-handler-domain` to some
domain you configure according to the instructions below, e.g.
`phabricator.example.com`. Once you set this key, emails will use a
'Reply-To' like `T123+273+af310f9220ad@phabricator.example.com`, which -- when
configured correctly, according to the instructions below -- will parse incoming
email and allow users to interact with Differential revisions, Maniphest tasks,
etc. over email.
If you don't want Phabricator to take up an entire domain (or subdomain) you
can configure a general prefix so you can use a single mailbox to receive mail
on. To make use of this set `metamta.single-reply-handler-prefix` to the
prefix of your choice, and Phabricator will prepend this to the 'Reply-To'
mail address. This works because everything up to the first (optional) '+'
character in an email-address is considered the receiver, and everything
after is essentially ignored.
You can also set up application email addresses to allow users to create
application objects via email. For example, you could configure
`bugs@phabricator.example.com` to create a Maniphest task out of any email
which is sent to it. To do this, see application settings for a given
application at
{nav icon=home, name=Home >
name=Applications >
icon=cog, name=Settings}
= Security =
The email reply channel is "somewhat" authenticated. Each reply-to address is
unique to the recipient and includes a hash of user information and a unique
object ID, so it can only be used to update that object and only be used to act
on behalf of the recipient.
However, if an address is leaked (which is fairly easy -- for instance,
forwarding an email will leak a live reply address, or a user might take a
screenshot), //anyone// who can send mail to your reply-to domain may interact
with the object the email relates to as the user who leaked the mail. Because
the authentication around email has this weakness, some actions (like accepting
revisions) are not permitted over email.
This implementation is an attempt to balance utility and security, but makes
some sacrifices on both sides to achieve it because of the difficulty of
authenticating senders in the general case (e.g., where you are an open source
project and need to interact with users whose email accounts you have no control
over).
If you leak a bunch of reply-to addresses by accident, you can change
`phabricator.mail-key` in your configuration to invalidate all the old hashes.
You can also set `metamta.public-replies`, which will change how Phabricator
delivers email. Instead of sending each recipient a unique mail with a personal
reply-to address, it will send a single email to everyone with a public reply-to
address. This decreases security because anyone who can spoof a "From" address
can act as another user, but increases convenience if you use mailing lists and,
practically, is a reasonable setting for many installs. The reply-to address
will still contain a hash unique to the object it represents, so users who have
not received an email about an object can not blindly interact with it.
If you enable application email addresses, those addresses also use the weaker
"From" authentication mechanism.
NOTE: Phabricator does not currently attempt to verify "From" addresses because
this is technically complex, seems unreasonably difficult in the general case,
and no installs have had a need for it yet. If you have a specific case where a
reasonable mechanism exists to provide sender verification (e.g., DKIM
signatures are sufficient to authenticate the sender under your configuration,
or you are willing to require all users to sign their email), file a feature
request.
= Testing and Debugging Inbound Email =
You can use the `bin/mail` utility to test and review inbound mail. This can
help you determine if mail is being delivered to Phabricator or not:
phabricator/ $ ./bin/mail list-inbound # List inbound messages.
phabricator/ $ ./bin/mail show-inbound # Show details about a message.
You can also test receiving mail, but note that this just simulates receiving
the mail and doesn't send any information over the network. It is
primarily aimed at developing email handlers: it will still work properly
if your inbound email configuration is incorrect or even disabled.
phabricator/ $ ./bin/mail receive-test # Receive test message.
Run `bin/mail help <command>` for detailed help on using these commands.
= Mailgun Setup =
To use Mailgun, you need a Mailgun account. You can sign up at
<http://www.mailgun.com>. Provided you have such an account, configure it
like this:
- Configure a mail domain according to Mailgun's instructions.
- Add a Mailgun route with a `catch_all()` rule which takes the action
`forward("https://phabricator.example.com/mail/mailgun/")`. Replace the
example domain with your actual domain.
- Set the `mailgun.api-key` config key to your Mailgun API key.
Postmark Setup
==============
To process inbound mail from Postmark, configure this URI as your inbound
webhook URI in the Postmark control panel:
```
https://<phabricator.yourdomain.com>/mail/postmark/
```
+See also the Postmark section in @{article:Configuring Outbound Email} for
+discussion of the remote address whitelist used to verify that requests this
+endpoint receives are authentic requests originating from Postmark.
+
= SendGrid Setup =
To use SendGrid, you need a SendGrid account with access to the "Parse API" for
inbound email. Provided you have such an account, configure it like this:
- Configure an MX record according to SendGrid's instructions, i.e. add
`phabricator.example.com MX 10 mx.sendgrid.net.` or similar.
- Go to the "Parse Incoming Emails" page on SendGrid
(<http://sendgrid.com/developer/reply>) and add the domain as the
"Hostname".
- Add the URL `https://phabricator.example.com/mail/sendgrid/` as the "Url",
using your domain (and HTTP instead of HTTPS if you are not configured with
SSL).
- If you get an error that the hostname "can't be located or verified", it
means your MX record is either incorrectly configured or hasn't propagated
yet.
- Set `metamta.reply-handler-domain` to `phabricator.example.com`"
(whatever you configured the MX record for).
That's it! If everything is working properly you should be able to send email
to `anything@phabricator.example.com` and it should appear in
`bin/mail list-inbound` within a few seconds.
= Local MTA: Installing Mailparse =
If you're going to run your own MTA, you need to install the PECL mailparse
extension. In theory, you can do that with:
$ sudo pecl install mailparse
You may run into an error like "needs mbstring". If so, try:
$ sudo yum install php-mbstring # or equivalent
$ sudo pecl install -n mailparse
If you get a linker error like this:
COUNTEREXAMPLE
PHP Warning: PHP Startup: Unable to load dynamic library
'/usr/lib64/php/modules/mailparse.so' - /usr/lib64/php/modules/mailparse.so:
undefined symbol: mbfl_name2no_encoding in Unknown on line 0
...you need to edit your php.ini file so that mbstring.so is loaded **before**
mailparse.so. This is not the default if you have individual files in
`php.d/`.
= Local MTA: Configuring Sendmail =
Before you can configure Sendmail, you need to install Mailparse. See the
section "Installing Mailparse" above.
Sendmail is very difficult to configure. First, you need to configure it for
your domain so that mail can be delivered correctly. In broad strokes, this
probably means something like this:
- add an MX record;
- make sendmail listen on external interfaces;
- open up port 25 if necessary (e.g., in your EC2 security policy);
- add your host to /etc/mail/local-host-names; and
- restart sendmail.
Now, you can actually configure sendmail to deliver to Phabricator. In
`/etc/aliases`, add an entry like this:
phabricator: "| /path/to/phabricator/scripts/mail/mail_handler.php"
If you use the `PHABRICATOR_ENV` environmental variable to select a
configuration, you can pass the value to the script as an argument:
.../path/to/mail_handler.php <ENV>
This is an advanced feature which is rarely used. Most installs should run
without an argument.
After making this change, run `sudo newaliases`. Now you likely need to symlink
this script into `/etc/smrsh/`:
sudo ln -s /path/to/phabricator/scripts/mail/mail_handler.php /etc/smrsh/
Finally, edit `/etc/mail/virtusertable` and add an entry like this:
@yourdomain.com phabricator@localhost
That will forward all mail to @yourdomain.com to the Phabricator processing
script. Run `sudo /etc/mail/make` or similar and then restart sendmail with
`sudo /etc/init.d/sendmail restart`.
diff --git a/src/docs/user/configuration/configuring_outbound_email.diviner b/src/docs/user/configuration/configuring_outbound_email.diviner
index d2daf7a40a..37a344c275 100644
--- a/src/docs/user/configuration/configuring_outbound_email.diviner
+++ b/src/docs/user/configuration/configuring_outbound_email.diviner
@@ -1,312 +1,329 @@
@title Configuring Outbound Email
@group config
Instructions for configuring Phabricator to send mail.
Overview
========
Phabricator can send outbound email through several different mail services,
including a local mailer or various third-party services. Options include:
| Send Mail With | Setup | Cost | Inbound | Notes |
|---------|-------|------|---------|-------|
| Mailgun | Easy | Cheap | Yes | Recommended |
| Postmark | Easy | Cheap | Yes | Recommended |
| Amazon SES | Easy | Cheap | No | Recommended |
| SendGrid | Medium | Cheap | Yes | Discouraged |
| External SMTP | Medium | Varies | No | Gmail, etc. |
| Local SMTP | Hard | Free | No | sendmail, postfix, etc |
| Custom | Hard | Free | No | Write a custom mailer for some other service. |
| Drop in a Hole | Easy | Free | No | Drops mail in a deep, dark hole. |
See below for details on how to select and configure mail delivery for each
mailer.
Overall, Mailgun and SES are much easier to set up, and using one of them is
recommended. In particular, Mailgun will also let you set up inbound email
easily.
If you have some internal mail service you'd like to use you can also
write a custom mailer, but this requires digging into the code.
Phabricator sends mail in the background, so the daemons need to be running for
it to be able to deliver mail. You should receive setup warnings if they are
not. For more information on using daemons, see
@{article:Managing Daemons with phd}.
Basics
======
Regardless of how outbound email is delivered, you should configure these keys
in your configuration:
- **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.
Configuring Mailers
===================
Configure one or more mailers by listing them in the the `cluster.mailers`
configuration option. Most installs only need to configure one mailer, but you
can configure multiple mailers to provide greater availability in the event of
a service disruption.
A valid `cluster.mailers` configuration looks something like this:
```lang=json
[
{
"key": "mycompany-mailgun",
"type": "mailgun",
"options": {
"domain": "mycompany.com",
"api-key": "..."
}
},
...
]
```
The supported keys for each mailer are:
- `key`: Required string. A unique name for this mailer.
- `type`: Required string. Identifies the type of mailer. See below for
options.
- `priority`: Optional string. Advanced option which controls load balancing
and failover behavior. See below for details.
- `options`: Optional map. Additional options for the mailer type.
The `type` field can be used to select these third-party mailers:
- `mailgun`: Use Mailgun.
- `ses`: Use Amazon SES.
- `sendgrid`: Use Sendgrid.
It also supports these local mailers:
- `sendmail`: Use the local `sendmail` binary.
- `smtp`: Connect directly to an SMTP server.
- `test`: Internal mailer for testing. Does not send mail.
You can also write your own mailer by extending
`PhabricatorMailImplementationAdapter`.
Once you've selected a mailer, find the corresponding section below for
instructions on configuring it.
Setting Complex Configuration
=============================
Mailers can not be edited from the web UI. If mailers could be edited from
the web UI, it would give an attacker who compromised an administrator account
a lot of power: they could redirect mail to a server they control and then
intercept mail for any other account, including password reset mail.
For more information about locked configuration options, see
@{article:Configuration Guide: Locked and Hidden Configuration}.
Setting `cluster.mailers` from the command line using `bin/config set` can be
tricky because of shell escaping. The easiest way to do it is to use the
`--stdin` flag. First, put your desired configuration in a file like this:
```lang=json, name=mailers.json
[
{
"key": "test-mailer",
"type": "test"
}
]
```
Then set the value like this:
```
phabricator/ $ ./bin/config set --stdin < mailers.json
```
For alternatives and more information on configuration, see
@{article:Configuration User Guide: Advanced Configuration}
Mailer: Mailgun
===============
Mailgun is a third-party email delivery service. You can learn more at
<http://www.mailgun.com>. Mailgun is easy to configure and works well.
To use this mailer, set `type` to `mailgun`, then configure these `options`:
- `api-key`: Required string. Your Mailgun API key.
- `domain`: Required string. Your Mailgun domain.
Mailer: Postmark
================
Postmark is a third-party email delivery serivice. You can learn more at
<https://www.postmarkapp.com/>.
To use this mailer, set `type` to `postmark`, then configure these `options`:
- `access-token`: Required string. Your Postmark access token.
+ - `inbound-addresses`: Optional list<string>. Address ranges which you
+ will accept inbound Postmark HTTP webook requests from.
+
+The default address list is preconfigured with Postmark's address range, so
+you generally will not need to set or adjust it.
+
+The option accepts a list of CIDR ranges, like `1.2.3.4/16` (IPv4) or
+`::ffff:0:0/96` (IPv6). The default ranges are:
+
+```lang=json
+[
+ "50.31.156.6/32"
+]
+```
+
+The default address ranges were last updated in February 2018, and were
+documented at: <https://postmarkapp.com/support/article/800-ips-for-firewalls>
Mailer: Amazon SES
==================
Amazon SES is Amazon's cloud email service. You can learn more at
<http://aws.amazon.com/ses/>.
To use this mailer, set `type` to `ses`, then configure these `options`:
- `access-key`: Required string. Your Amazon SES access key.
- `secret-key`: Required string. Your Amazon SES secret key.
- `endpoint`: Required string. Your Amazon SES endpoint.
NOTE: Amazon SES **requires you to verify your "From" address**. Configure
which "From" address to use by setting "`metamta.default-address`" in your
config, then follow the Amazon SES verification process to verify it. You
won't be able to send email until you do this!
Mailer: SendGrid
================
SendGrid is a third-party email delivery service. You can learn more at
<http://sendgrid.com/>.
You can configure SendGrid in two ways: you can send via SMTP or via the REST
API. To use SMTP, configure Phabricator to use an `smtp` mailer.
To use the REST API mailer, set `type` to `sendgrid`, then configure
these `options`:
- `api-user`: Required string. Your SendGrid login name.
- `api-key`: Required string. Your SendGrid API key.
NOTE: Users have experienced a number of odd issues with SendGrid, compared to
fewer issues with other mailers. We discourage SendGrid unless you're already
using it.
Mailer: Sendmail
================
This requires a `sendmail` binary to be installed on
the system. Most MTAs (e.g., sendmail, qmail, postfix) should do this, but your
machine may not have one installed by default. For install instructions, consult
the documentation for your favorite MTA.
Since you'll be sending the mail yourself, you are subject to things like SPF
rules, blackholes, and MTA configuration which are beyond the scope of this
document. If you can already send outbound email from the command line or know
how to configure it, this option is straightforward. If you have no idea how to
do any of this, strongly consider using Mailgun or Amazon SES instead.
To use this mailer, set `type` to `sendmail`. There are no `options` to
configure.
Mailer: STMP
============
You can use this adapter to send mail via an external SMTP server, like Gmail.
To use this mailer, set `type` to `smtp`, then configure these `options`:
- `host`: Required string. The hostname of your SMTP server.
- `user`: Optional string. Username used for authentication.
- `password`: Optional string. Password for authentication.
- `protocol`: Optional string. Set to `tls` or `ssl` if necessary. Use
`ssl` for Gmail.
Disable Mail
============
To disable mail, just don't configure any mailers.
Testing and Debugging Outbound Email
====================================
You can use the `bin/mail` utility to test, debug, and examine outbound mail. In
particular:
phabricator/ $ ./bin/mail list-outbound # List outbound mail.
phabricator/ $ ./bin/mail show-outbound # Show details about messages.
phabricator/ $ ./bin/mail send-test # Send test messages.
Run `bin/mail help <command>` for more help on using these commands.
You can monitor daemons using the Daemon Console (`/daemon/`, or click
**Daemon Console** from the homepage).
Priorities
==========
By default, Phabricator will try each mailer in order: it will try the first
mailer first. If that fails (for example, because the service is not available
at the moment) it will try the second mailer, and so on.
If you want to load balance between multiple mailers instead of using one as
a primary, you can set `priority`. Phabricator will start with mailers in the
highest priority group and go through them randomly, then fall back to the
next group.
For example, if you have two SMTP servers and you want to balance requests
between them and then fall back to Mailgun if both fail, configure priorities
like this:
```lang=json
[
{
"key": "smtp-uswest",
"type": "smtp",
"priority": 300,
"options": "..."
},
{
"key": "smtp-useast",
"type": "smtp",
"priority": 300,
"options": "..."
},
{
"key": "mailgun-fallback",
"type": "mailgun",
"options": "..."
}
}
```
Phabricator will start with servers in the highest priority group (the group
with the **largest** `priority` number). In this example, the highest group is
`300`, which has the two SMTP servers. They'll be tried in random order first.
If both fail, Phabricator will move on to the next priority group. In this
example, there are no other priority groups.
If it still hasn't sent the mail, Phabricator will try servers which are not
in any priority group, in the configured order. In this example there is
only one such server, so it will try to send via Mailgun.
Next Steps
==========
Continue by:
- @{article:Configuring Inbound Email} so users can reply to email they
receive about revisions and tasks to interact with them; or
- learning about daemons with @{article:Managing Daemons with phd}; or
- returning to the @{article:Configuration Guide}.

File Metadata

Mime Type
text/x-diff
Expires
Mon, Apr 28, 10:07 AM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
107920
Default Alt Text
(28 KB)

Event Timeline