phacility/phabricator · info · PhabricatorMetaMTAReceivedMailProcessingException

err:self

err:self

Error message

Ignoring email with '%s' header to avoid loops.

What it means

dropMailFromPhabricator() runs early in received-mail processing and throws STATUS_FROM_PHABRICATOR whenever the inbound message carries the 'X-Phabricator-Sent-This-Message' header. Phabricator stamps every outbound mail with that header, so any inbound copy of it is Phabricator's own output coming back (e.g. via a loop where the public bug address is also a user's account email). Dropping it immediately prevents infinite mail loops; the status is also one of the two for which no error email is sent back.

Solutions

  1. Fix the routing rule that forwards Phabricator's own outbound mail back into an inbound Phabricator address — this status means loop protection fired, which is correct behavior.
  2. When testing inbound mail, compose a NEW message to the application address instead of forwarding a Phabricator notification.
  3. Admins: ensure the addresses Phabricator sends from (noreply/reserved) are never also configured as application receive addresses or members of a forwarded group.
  4. Check MetaMTA > Received Mail: STATUS_FROM_PHABRICATOR rows show which address looped; remove that mapping.

Example fix

// before: mail rule forwards everything, including notifications
// noreply@ -> bugs@phabricator.example
// notification carries X-Phabricator-Sent-This-Message -> err:self, dropped

// after: exclude Phabricator-sent mail from the forwarding rule
// if (header X-Phabricator-Sent-This-Message exists) do not forward
Defensive patterns

Strategy: try-catch

Validate before calling

// If you implement a mail-ingest script, mirror the guard before doing work:
if ($received_mail->getHeader('x-phabricator-sent-this-message')) {
  // this is Phabricator's own output coming back: drop, never auto-forward it
  return;
}

Try / catch

try {
  $received_mail->processIncomingMail($sender);
} catch (PhabricatorMetaMTAReceivedMailProcessingException $ex) {
  if ($ex->getStatusCode() === MetaMTAReceivedMailStatus::STATUS_FROM_PHABRICATOR) {
    return; // loop protection fired: fix routing, do not requeue
  }
  throw $ex;
}

Prevention

When it happens

Trigger: An email arrives whose headers include X-Phabricator-Sent-This-Message (Phabricator's own stamp). Typical loop: Phabricator notifies user X at an address that aliases back into a Phabricator inbound address; or a mail rule auto-forwards all mail (including Phabricator notifications) to a Phabricator application address; or reply-all where the notification's own sender address loops back in.

Common situations: Auto-forwarding rules on shared mailboxes; the install's notification address being subscribed to its own application address; mailing-list gateways that bounce delivered mail back to Phabricator; testing inbound mail by forwarding an outbound notification by hand.

Related errors


AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21). Data as JSON: /api/errors/8c838230d1ff502a. Report an issue: GitHub.

Appendix: source

Thrown at src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php:368

      foreach (explode(',', $addresses) as $address) {
        $raw_addresses[] = $this->getRawEmailAddress($address);
      }
    }

    return array_filter($raw_addresses);
  }

  /**
   * If Phabricator sent the mail, always drop it immediately. This prevents
   * loops where, e.g., the public bug address is also a user email address
   * and creating a bug sends them an email, which loops.
   */
  private function dropMailFromPhabricator() {
    if (!$this->getHeader('x-phabricator-sent-this-message')) {
      return;
    }

    throw new PhabricatorMetaMTAReceivedMailProcessingException(
      MetaMTAReceivedMailStatus::STATUS_FROM_PHABRICATOR,
      pht(
        "Ignoring email with '%s' header to avoid loops.",
        'X-Phabricator-Sent-This-Message'));
  }

  /**
   * If this mail has the same message ID as some other mail, and isn't the
   * first mail we we received with that message ID, we drop it as a duplicate.
   */
  private function dropMailAlreadyReceived() {
    $message_id_hash = $this->getMessageIDHash();
    if (!$message_id_hash) {
      // No message ID hash, so we can't detect duplicates. This should only
      // happen with very old messages.
      return;
    }

View on GitHub (pinned to 5720a38cfe)