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.
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|
|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.
By default, Phabricator uses a firstname.lastname@example.org 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:
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 T123email@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 firstname.lastname@example.org, 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.
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.
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.
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:
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:
That's it! If everything is working properly you should be able to send email to email@example.com and it should appear in bin/mail list-inbound within a few seconds.
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:
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/.
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:
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 <ENV>"
...where <ENV> is the PHABRICATOR_ENV the script should run under. 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:
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.
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)