Page MenuHomePhabricator

Creating access-restricted tasks from email (e.g. security tasks)
Open, LowPublicFeature

Description

I know we can do https://www.mediawiki.org/wiki/Phabricator/Help#Using_email

But I'm lazy, and I'd like to be able to forward emails (ie post some triage) that are sent to security@, and have a task created, visibility policies applied, and attachments attached (with correct visibility set).

Currently, doing the first part manually is easy, but when I upload attachments, I have to manually fix the visibility for each...

Event Timeline

Restricted Application added a subscriber: Aklapper. · View Herald Transcript
Aklapper changed the subtype of this task from "Task" to "Feature Request".
Aklapper edited projects, added: Phabricator (Upstream), Upstream; removed: Phabricator.

This ticket seems to mix "Somehow set view policy for tasks created via email" and "Attachments are not attached on tasks created via email" (example, please) ?
That's more than one issue per task and thus not actionable. ;)

Selecting a specific view or edit policy is not supported per https://we.phorge.it/applications/mailcommands/PhabricatorManiphestApplication/task/ (and I have a hard time to imagine how that should be expressed in plain text).
Might be slightly easier to implement now that Named Reusable Policies exist since https://we.phorge.it/T15277 but sounds still pretty error-prone.
See https://we.phorge.it/source/phorge/browse/master/src/applications/maniphest/command/ for "email commands" currently in store; see https://we.phorge.it/source/phorge/browse/master/src/applications/metamta/parser/PhabricatorMetaMTAEmailBodyParser.php for all the parseBody() phun.

Alternatively we can write a (e.g. Python) script that reads a .eml and create a task.

sbassett subscribed.

Back-ordering for now.

This ticket seems to mix "Somehow set view policy for tasks created via email" and "Attachments are not attached on tasks created via email" (example, please) ?
That's more than one issue per task and thus not actionable. ;)

I've not tried to create a task via email and include attachments; no idea if/how that works.

I'm complaining that currently to create the reports in phabricator I have to manually copy text over, add the attachments, and then fix the visibility on them all manually, individually on each.

It would be much easier if I (and others) can just forward the emails that come in, and have that create phab tasks, with attachments attached properly, with the correct visibility set etc.

The case of attachments being attached only viewable to the uploader is a (known?) different issue.

Aklapper renamed this task from Creating security tasks from email to Creating access-restricted tasks from email (e.g. security tasks).EditedAug 13 2026, 9:47 AM

If validation of policy identifiers in upstream wasn't such a clusterfuck (basically non-existing) this would be pretty straight-forward:

commit f5dd620ff04fc7d0291e214c483ddb75ccef6ade
Author: Andre Klapper <aklapper@wikimedia.org>
Date:   Thu Aug 13 07:45:25 2026 -0200

    Kind of allow setting view policy on tasks created via inbound email
    
    Summary:
    This sentence no verb. But T434536.
    
    Test Plan:
    * Set up inbound email via http://phorge.localhost/applications/panel/PhabricatorManiphestApplication/email/
    * Create tasks via email, including a line
    ** `!view-policy nonsense` (fails)
    ** `!view-policy more nonsense` (fails)
    ** `!view-policy no-one` (fails though valid because T16695)
    ** `!view-policy admin` (fails though valid because T16695)
    ** `!view-policy PHID-PLCY-nonsense` (passes though invalid because T16695)
    ** `!view-policy PHID-NPLC-nonsense` (passes though invalid because T16695)
    ** `!view-policy PHID-PLCY-oneexistingvalidphid` (passes and valid)
    ** `!view-policy PHID-NPLC-oneexistingvalidphid` (passes and valid)
    * Spot more docs at http://phorge.localhost/applications/mailcommands/PhabricatorManiphestApplication/task/

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index e4f3b7f9e1..447d2b3349 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1879,6 +1879,7 @@ phutil_register_library_map(array(
     'ManiphestTransactionQuery' => 'applications/maniphest/query/ManiphestTransactionQuery.php',
     'ManiphestUpdateConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestUpdateConduitAPIMethod.php',
     'ManiphestView' => 'applications/maniphest/view/ManiphestView.php',
+    'ManiphestViewPolicyEmailCommand' => 'applications/maniphest/command/ManiphestViewPolicyEmailCommand.php',
     'MetaMTAEmailTransactionCommand' => 'applications/metamta/command/MetaMTAEmailTransactionCommand.php',
     'MetaMTAEmailTransactionCommandTestCase' => 'applications/metamta/command/__tests__/MetaMTAEmailTransactionCommandTestCase.php',
     'MetaMTAMailReceivedGarbageCollector' => 'applications/metamta/garbagecollector/MetaMTAMailReceivedGarbageCollector.php',
@@ -7984,6 +7985,7 @@ phutil_register_library_map(array(
     'ManiphestTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
     'ManiphestUpdateConduitAPIMethod' => 'ManiphestConduitAPIMethod',
     'ManiphestView' => 'AphrontView',
+    'ManiphestViewPolicyEmailCommand' => 'ManiphestEmailCommand',
     'MetaMTAEmailTransactionCommand' => 'Phobject',
     'MetaMTAEmailTransactionCommandTestCase' => 'PhabricatorTestCase',
     'MetaMTAMailReceivedGarbageCollector' => 'PhabricatorGarbageCollector',
diff --git a/src/applications/maniphest/command/ManiphestViewPolicyEmailCommand.php b/src/applications/maniphest/command/ManiphestViewPolicyEmailCommand.php
new file mode 100644
index 0000000000..0ad602bb6b
--- /dev/null
+++ b/src/applications/maniphest/command/ManiphestViewPolicyEmailCommand.php
@@ -0,0 +1,68 @@
+<?php
+
+final class ManiphestViewPolicyEmailCommand
+  extends ManiphestEmailCommand {
+
+  public function getCommand() {
+    return 'view-policy';
+  }
+
+  public function getCommandSyntax() {
+    return '**!view-policy** //phid//';
+  }
+
+  public function getCommandSummary() {
+    return pht('Set a view policy on a task.');
+  }
+
+  public function getCommandDescription() {
+    return pht(
+      'Pass the PHID of a policy or the PHID of a named policy to set a '.
+      'non-default view policy on a task.'."\n\n".
+      'If you omit the phid or the policy is not valid, visibility will be '.
+      'restricted to the task author as a precaution.');
+  }
+
+  public function buildTransactions(
+    PhabricatorUser $viewer,
+    PhabricatorApplicationTransactionInterface $object,
+    PhabricatorMetaMTAReceivedMail $mail,
+    $command,
+    array $argv) {
+
+    $xactions = array();
+    $policy_phid = null;
+    $policy_passed = head($argv);
+
+    if ($policy_passed) {
+      $phid_type = phid_get_type($policy_passed);
+      switch ($phid_type) {
+        case PhorgePolicyPHIDTypeNamedPolicy::TYPECONST:
+        case PhabricatorPolicyPHIDTypePolicy::TYPECONST:
+          $policy_found = id(new PhabricatorPolicyQuery())
+            ->setViewer($viewer)
+            ->withPHIDs(array($policy_passed))
+            ->executeOne();
+          if ($policy_found) {
+            $policy_phid = $policy_found->getPHID();
+          }
+        default:
+          // We received a named policy name or random string which is
+          // impossible to validate due to T16695 (PhabricatorPolicyQuery will
+          // always return an object handle), thus not supported currently.
+          break;
+      }
+    }
+    // Treat no valid policy like user-only, to avoid unwanted data exposure.
+    if (!$policy_phid) {
+      $policy_phid = $viewer->getPHID();
+    }
+
+    $xactions[] = $object->getApplicationTransactionTemplate()
+      ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
+      ->setNewValue($policy_phid);
+
+    return $xactions;
+  }
+
+}

I mean, we could put that code above into our downstream instance if you want to, it's cheap.
But it's error-prone and not convenient, as you need to remember and have to manually add some PHID-PLCY-* string.