mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-23 15:22:41 +01:00
84dcf9045c
Summary: While not explicitly misleading, this document can do a better job of covering the common/modern case. Test Plan: Read document. Reviewers: rush898, btrahan Reviewed By: btrahan Subscribers: epriestley Differential Revision: https://secure.phabricator.com/D10783
259 lines
11 KiB
Text
259 lines
11 KiB
Text
@title Configuring Inbound Email
|
|
@group config
|
|
|
|
This document contains instructions for configuring inbound email, so users
|
|
may update Differential and Maniphest by replying to messages and create
|
|
Maniphest tasks 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 |
|
|
| 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, set these configuration keys:
|
|
|
|
- ##metamta.differential.reply-handler-domain##: enables email replies for
|
|
Differential.
|
|
- ##metamta.maniphest.reply-handler-domain##: enables email replies for
|
|
Maniphest.
|
|
|
|
Set these keys to some domain which you configure according to the instructions
|
|
below, e.g. `phabricator.example.com`. You can set these both to the same
|
|
domain, and will generally want to. Once you set these keys, emails will use a
|
|
'Reply-To' like `T123+273+af310f9220ad@example.com`, which -- when
|
|
configured correctly, according to the instructions below -- will parse incoming
|
|
email and allow users to interact with Maniphest tasks and Differential
|
|
revisions 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 a task creation email address, like `bugs@example.com`,
|
|
which will create a Maniphest task out of any email which is set to it. To do
|
|
this, set `metamta.maniphest.public-create-email` in your configuration. This
|
|
has some mild security implications, see below.
|
|
|
|
= 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 `metamta.maniphest.public-create-email`, that address also uses
|
|
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.
|
|
|
|
= 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.maniphest.reply-handler-domain## and/or
|
|
##metamta.differential.reply-handler-domain## to
|
|
"##phabricator.example.com##" (whatever you configured the MX record for),
|
|
depending on whether you want to support email replies for Maniphest,
|
|
Differential, or both.
|
|
|
|
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`.
|
|
|
|
= Local MTA: Configuring Lamson =
|
|
|
|
Before you can configure Lamson, you need to install Mailparse. See the section
|
|
"Installing Mailparse" above.
|
|
|
|
In contrast to Sendmail, Lamson is relatively easy to configure. It is fairly
|
|
minimal, and is suitable for a development or testing environment. Lamson
|
|
listens for incoming SMTP mails and passes the content directly to Phabricator.
|
|
|
|
To get started, follow the provided instructions
|
|
(<http://lamsonproject.org/docs/getting_started.html>) to set up an instance.
|
|
One likely deployment issue is that binding to port 25 requires root
|
|
privileges. Lamson is capable of starting as root then dropping privileges, but
|
|
you must supply ##-uid## and ##-gid## arguments to do so, as demonstrated by
|
|
Step 8 in Lamson's deployment tutorial (located here:
|
|
<http://lamsonproject.org/docs/deploying_oneshotblog.html>).
|
|
|
|
The Lamson handler code itself is very concise; it merely needs to pass the
|
|
content of the email to Phabricator:
|
|
|
|
import logging, subprocess
|
|
from lamson.routing import route, stateless
|
|
from lamson import view
|
|
|
|
PHABRICATOR_ROOT = "/path/to/phabricator"
|
|
PHABRICATOR_ENV = "custom/myconf"
|
|
LOGGING_ENABLED = True
|
|
|
|
@route("(address)@(host)", address=".+")
|
|
@stateless
|
|
def START(message, address=None, host=None):
|
|
if LOGGING_ENABLED:
|
|
logging.debug("%s", message.original)
|
|
process = subprocess.Popen([PHABRICATOR_ROOT + "scripts/mail/mail_handler.php",PHABRICATOR_ENV],stdin=subprocess.PIPE)
|
|
process.communicate(message.original)
|