Matrix: M28M29M34
Open in panel — /app/fbl
Sending

OmniFBL Feedback Loop

OmniFBL is PostMTA's multi-ISP feedback loop aggregation system. It ingests ARF-format complaint reports from five ISP sources, normalises them into a unified internal model, and drives both the suppression list and Kumo Shaping reputation engine in real time.

Matrix refs: M28 (Shaping)   M29 (Warmup)   M34 (FBL Ingest)

FBL Overview

A Feedback Loop (FBL) is a service offered by large ISPs (Gmail, Microsoft, Yahoo, Apple, etc.) that forwards complaint reports — messages their users mark as spam — back to the sending MTA via a standardised Abuse Feedback Reporting Format (ARF, RFC 5965) message.

PostMTA operates feedback-monitor@postmaster.<sending-domain> as the ingestion address. When a recipient clicks "Report Spam" in their mail client, the ISP forwards the original message (or its headers) to this address. OmniFBL processes that report and:

  1. Extracts the complained-about recipient address.
  2. Suppresses that address in the subuser's suppression list (30-day TTL).
  3. Applies a reputation penalty to the sending subuser's Kumo Shaping epoch.
  4. Optionally forwards the raw ARF to a SIEM or security data pipeline.

ARF / RFC 5965 Message Structure

ARF messages are MIME multipart messages with two body parts. Part 1 contains the original message headers (the reported message). Part 2 contains a JSON or plain-text feedback report with machine-readable metadata.

Content-Type: message/feedback-report
From: abuse@hotmail.com
To: postmaster@example.com
Subject: Feedback Report
MIME-Version: 1.0

--boundary
Content-Type: text/rfc822-headers
Content-Disposition: inline

From: newsletter@example.com
To: recipient@hotmail.com
Subject: July Newsletter
DKIM-Signature: v=1; a=rsa-sha256; d=example.com...
Received: from mail.example.com (192.0.2.1) ...

--boundary
Content-Type: application/json
Content-Disposition: inline

{
  "feedbackType": "abuse",
  "userAgent": "Microsoft Outlook/16.0",
  "arrivalDate": "2026-07-18T09:15:00Z",
  "messageId": "",
  "reportedDomain": "example.com",
  "gateway": "Hotmail FBL"
}
--boundary--

OmniFBL supports the following feedbackType values from RFC 5965:

ISP Sources

OmniFBL maintains a separate ingress channel for each ISP. Configuration for each source is in Settings → Feedback Loops:

ISPFBL Address PatternARF VariantRequiresLatency
GmailPostMTA-managed (abuse reports go to Gmail's FBL registration)Gmail ARF extensionDMARC p=quarantine/reject + DKIM pass< 5 min
Microsoft (Hotmail / Outlook / Live)feedback-monitor@postmaster.<domain>Standard RFC 5965 + JMR headersSPF aligned + DKIM pass< 10 min
YahooRegistered via Yahoo Postmaster ToolsYahoo ARF variantDMARC p=reject + domain verification< 15 min
Apple (iCloud / Me.com)SAML assertion to Apple FBL endpointApple Feedback ID formatApple FBL opt-in approval< 30 min
Custom ISPOperator-configured email addressRFC 5965 or JSONManual ISP registrationVariable
Gmail DMARC requirement: Gmail only forwards complaint reports for domains with DMARC policy set to p=quarantine or p=reject. Domains with p=none are not eligible for Gmail FBL.

Complaint Pipeline Flow

Every ARF report passes through the following deterministic pipeline:

1.  FBL Ingress
    MUA reports message as spam via ISP abuse button
    ISP forwards ARF report to PostMTA's feedback-monitor address
    Mail transport agent (MX) receives the ARF MIME message
    SMTP envelope: MAIL FROM:<> (null return path)

2.  ARF Parse
    Extract Feedback-Type (abuse / fraud / dsn)
    Extract original message headers (From / To / Message-ID / DKIM)
    Validate that reported domain matches a verified sending domain
    Reject malformed ARF with PMH-FBL-004

3.  Suppress
    Normalize complaint recipient address (lowercase, strip + addressing)
    Write record to complaints cache: recipient / source_isp / reported_at
    Add to subuser suppression list with 30-day TTL

4.  Shape
    Read current reputation delta from complaints cache
    Apply reputation penalty: -0.02 per unique complaint in rolling 7-day window
    If subuser complaint rate exceeds 0.1%:
        Flag for operator review
        If complaint rate > 0.3%:
            Demote subuser epoch by 2 levels
            Log event type complaint_demote

Address Normalisation

Before writing to the suppression list, OmniFBL normalises the recipient address using the same rules as the sending pipeline:

OmniFBL vs Traditional FBL

+------------------+---------------------------+---------------------------+
| Feature          | Traditional FBL           | OmniFBL                   |
+------------------+---------------------------+---------------------------+
| ISP sources      | 1 (single feedback loop)  | 5 (Gmail/Microsoft/       |
|                  |                           | Yahoo/Apple/custom)       |
| Format handling  | One fixed parser          | Per-ISP ARF variant parser|
| Suppression sync | Manual via dashboard       | Automatic within 60s      |
| Shaping coupling | None                      | Reputation penalty applied |
|                  |                           | to epoch on each complaint|
| Complaint rate   | Aggregate only            | Per-ISP and aggregate     |
| alerting         |                           | with configurable阈值      |
| SIEM export      | Syslog only               | Webhook + Kafka + S3      |
| Header injection | None                      | X-PMH-FBL-* trace headers |
| Encryption       | STARTTLS optional         | MTA-STS enforced          |
| Deduplication    | None                      | SHA256(recipient+source)  |
+------------------+---------------------------+---------------------------+

Complaint Rate SQL Query

Use this query to monitor complaint rate per subuser over a rolling 7-day window. Alert threshold is configurable but defaults to 0.1%.

-- Complaint rate per subuser, rolling 7-day window
SELECT
  subuser_id,
  date_trunc('day', reported_at') AS day,
  COUNT(DISTINCT recipient_address)        AS unique_complaints,
  COUNT(DISTINCT recipient_address) * 100.0
    / NULLIF((
      SELECT COUNT(DISTINCT recipient_address)
      FROM message_events
      WHERE event_type = 'delivered'
        AND subuser_id = c.subuser_id
        AND event_time >= NOW() - INTERVAL '7 days'
    ), 0)                                 AS complaint_rate_pct,
  (
    SELECT COUNT(*)
    FROM shaping_epochs
    WHERE subuser_id = c.subuser_id
      AND date(next_epoch_at) = CURRENT_DATE
  )                                       AS current_epoch
FROM complaints c
WHERE reported_at >= NOW() - INTERVAL '7 days'
GROUP BY subuser_id, day
ORDER BY complaint_rate_pct DESC;
Alert thresholds: When complaint_rate_pct exceeds 0.1%, PostMTA generates a complaint_threshold_exceeded event. At 0.3%, the subuser's Kumo Shaping epoch is demoted by 2 levels and a PagerDuty alert fires. Configure thresholds in Settings → Alerting → Complaint Rate.

SIEM Export

Raw ARF events can be forwarded to a SIEM (Splunk, Elastic, Sumo Logic, etc.) via webhook, Kafka, or S3. The export API supports NDJSON and CSV formats and allows filtering by ISP source and feedback type.

POST /v1/fbl/siem/export
Content-Type: application/json
Authorization: Bearer pmta_live_...

{
  "start_time": "2026-07-01T00:00:00Z",
  "end_time":   "2026-07-18T23:59:59Z",
  "format":     "ndjson",
  "destination": {
    "type": "webhook",
    "url":  "https://siem.example.com/ingest/postmta-fbl"
  },
  "filters": {
    "source_isp": ["gmail", "microsoft"],
    "feedback_type": ["abuse"]
  }
}

-- Response:
{
  "export_id":   "fbl_exp_01HX...",
  "status":      "queued",
  "record_count": null,
  "eta_seconds":  120,
  "webhook_secret": "fbl_whsec_..."
}

Supported SIEM destination types:

X-PMH-FBL-* Trace Headers

OmniFBL injects the following trace headers into messages it processes, visible in the raw email headers of any suppression event:

HeaderDescription
X-PMH-FBL-Source-ISPISP that originated the complaint (gmail / microsoft / yahoo / apple / custom)
X-PMH-FBL-Feedback-TypeARF feedback type (abuse / fraud / dsn)
X-PMH-FBL-Reported-AtISO 8601 timestamp when ISP received the complaint
X-PMH-FBL-Complaint-IDUnique OmniFBL internal ID for deduplication
X-PMH-FBL-Processed-AtISO 8601 timestamp when OmniFBL processed this report

Deduplication

OmniFBL deduplicates complaints using a SHA-256 hash of the normalised recipient address and ISP source. If the same recipient submits multiple complaints for the same ISP within 24 hours, only the first is processed. Subsequent duplicates are logged with duplicate_suppressed and discarded.

FBL Error Codes

CodeMeaningAction
PMH-FBL-001Malformed ARF message (missing feedback-type)Log and discard; increment error counter
PMH-FBL-002Reported domain not verified in PostMTAHard block; alert operator
PMH-FBL-003DKIM signature did not verify on reported messageLog; do not suppress; flag for review
PMH-FBL-004ARF parse failure (invalid MIME structure)Log and discard; increment error counter
PMH-FBL-005ISP source not registeredReject at MTA envelope stage