Skip to content

[Feature] Expose milter headers in legacy RSPAMC protocol#5948

Merged
vstakhov merged 2 commits intomasterfrom
vstakhov-exim-headers
Mar 25, 2026
Merged

[Feature] Expose milter headers in legacy RSPAMC protocol#5948
vstakhov merged 2 commits intomasterfrom
vstakhov-exim-headers

Conversation

@vstakhov
Copy link
Copy Markdown
Member

@vstakhov vstakhov commented Mar 21, 2026

Summary

  • Expose milter add/remove headers in the legacy RSPAMC and SPAMC text protocol output
  • Add extended symbol info (descriptions and options) via X-Symbol: lines
  • Backward compatible: existing Symbol: lines unchanged

Problem

Legacy RSPAMC clients (notably Exim via spam = nobody:true with variant=rspamd) only see scores, actions, and symbol names. Milter headers (X-CTCH-, X-CM-, X-Spamd-Result, etc.) and symbol options/descriptions are invisible — they only appear in the JSON response used by HTTP clients.

This blocks Exim users from accessing custom headers added by modules (e.g., Cyren/CTASD, Cloudmark) for false-positive/false-negative reporting.

New protocol lines

Milter header operations

X-Milter-Add: Header-Name: value             # append header
X-Milter-Add: Header-Name[N]: value          # insert at position N
X-Milter-Del: Header-Name                    # remove all instances
X-Milter-Del: Header-Name[N]                 # remove Nth instance

Extended symbol info

X-Symbol: BAYES_SPAM(5.00); Bayes spam probability
X-Symbol: RBL_SPAMHAUS(3.00); Spamhaus RBL [127.0.0.2, sbl.spamhaus.org]
X-Symbol: CTCH_SPAM(5.00); Cyren CTCH [refid:str123]

Format: X-Symbol: NAME(SCORE); DESCRIPTION [OPT1, OPT2, ...]

Exim usage example

warn
  spam = nobody:true
  set acl_m_report = ${sg{$spam_report}{\\v\\s+}{\n}}

  # Add milter headers: filter X-Milter-Add lines, strip prefix + optional [N]
  set acl_m_milter_add = ${sg{\
    ${sg{$acl_m_report}{(?m)^(?!X-Milter-Add: ).*(\n|$)}{}}}\
    {(?m)^X-Milter-Add: ([^\[:\n]+)(?:\[\d+\])?: }{$1: }}
  add_header = $acl_m_milter_add

  # Remove milter headers: filter X-Milter-Del lines, strip prefix + optional [N]
  set acl_m_milter_del = ${sg{\
    ${sg{$acl_m_report}{(?m)^(?!X-Milter-Del: ).*(\n|$)}{}}}\
    {(?m)^X-Milter-Del: ([^\[\n]+).*}{$1}}
  remove_header = $acl_m_milter_del

Test plan

  • Build and run unit tests
  • Test with rspamc CLI (SYMBOLS method) and verify new lines appear
  • Test with Exim variant=rspamd and verify $spam_report contains the new lines
  • Verify existing Symbol: lines unchanged (backward compatibility)
  • Test with milter_headers module producing both add and remove operations

…/SPAMC protocol

Previously, milter add/remove headers and symbol options were only
available via the JSON (HTTP) protocol. Legacy RSPAMC clients like
Exim had no way to access them through $spam_report.

This adds three new line types to the legacy text protocol output:

- X-Milter-Add: Header: value — milter headers to add (with optional
  [N] position bracket for insert-at-position)
- X-Milter-Del: Header — milter headers to remove (with optional [N]
  for specific instance removal)
- X-Symbol: Name(score); description [opt1, opt2] — extended symbol
  info with descriptions and options

Existing Symbol: lines are preserved for backward compatibility.
Tests RSPAMC and SPAMC protocol output for:
- X-Milter-Add: lines (add headers)
- X-Milter-Del: lines (remove headers)
- X-Symbol: lines (extended symbol info with options)
- Backward compatibility of existing Symbol: lines

Also fix rspamc()/spamc() test helpers to read full response
instead of truncating at 2048 bytes.
@vstakhov vstakhov marked this pull request as ready for review March 21, 2026 12:17
@vstakhov vstakhov merged commit ab0ab7b into master Mar 25, 2026
27 checks passed
@vstakhov vstakhov deleted the vstakhov-exim-headers branch March 25, 2026 08:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant