Suped

What does the SpamAssassin rule FONT_INVIS_MSGID test for?

Published 3 Jun 2025
Updated 15 Oct 2026
10 min read
Summarize with
SpamAssassin FONT_INVIS_MSGID rule for invisible HTML text and Message-ID context.
Updated on 18 Oct 2026: We clarified FONT_INVIS_MSGID scoring and MIME decoding, and added commands to reproduce the rule locally.
The FONT_INVIS_MSGID rule correlates font-hidden HTML with a host-shaped Message-ID suffix, then applies exceptions for several normal mail-path clues. SpamAssassin publishes the short description "Invisible text + suspicious message ID", but the underlying test does not simply declare a Message-ID invalid or compare its domain with the From address.
Treat the result as a correlation warning. The body contains HTML that matched the tiny-font or transparent-color test, the Message-ID matched an internal host-pattern helper, and none of the rule's listed exceptions suppressed the hit. A normal-looking Message-ID can therefore appear in a message that triggers the rule.

What FONT_INVIS_MSGID tests for

In SpamAssassin's upstream rule source, FONT_INVIS_MSGID is a meta rule. One subtest scans HTML for specific font-hiding patterns. Another helper, __MSGID_OK_HOST, checks for a host-like pattern in the Message-ID. The final expression then excludes messages with specified relay, header, or MIME clues. Troubleshooting requires the installed rule expression because rule updates can change it.
  1. Hidden HTML: The raw-body test matches specific font or font-size spellings, including 0px and 1px, or transparent color, with an ASCII letter or digit immediately after the tag. It is a pattern match, not a browser visibility test.
  2. Message-ID shape: The header helper uses a loose pattern after @. It does not resolve the host in DNS or validate the complete Message-ID.
  3. Benign exceptions: Relay naming, Errors-To, mail links, quoted-printable MIME, campaign IDs, thread indexes, and other clues can suppress the published hit.
  4. Score impact: The upstream score file assigns about 2.5 points. Rule updates, the selected score set, and local overrides determine the installed value.
Rule logic, shown as pseudocodetext
__FONT_INVIS_MSGID = __FONT_INVIS && __MSGID_OK_HOST FONT_INVIS_MSGID = __FONT_INVIS_MSGID && !__RCD_RDNS_MX_MESSY && !__RCD_RDNS_MX && !__HAS_ERRORS_TO && !__RCD_RDNS_MAIL && !__MAIL_LINK && !__HDR_RCVD_AMAZON && !__MIME_QP && !__HAS_CAMPAIGNID && !__HAS_THREAD_INDEX && !__RCD_RDNS_MTA
Do not assume the Message-ID is malformed
The helper name __MSGID_OK_HOST matters. A hit does not prove that the ID is invalid, reused, or mismatched with the sender. Inspect the matched HTML first, then validate the Message-ID separately if the raw header shows a real syntax or generation problem.
SpamAssassin adds the rule's points to the total spam score. The default required_score is 5.0, so a 2.5-point hit alone is below that threshold. The receiver controls its threshold and delivery action. The configuration manual explains scoring and overrides.
A rawbody test reads text after base64 or quoted-printable decoding while preserving HTML tags. Decode the HTML MIME part before searching for styles. The __MIME_QP exception is a separate condition in this meta rule; changing transfer encoding is not a template fix. See the raw-body rule documentation.

Why invisible text matters

Hidden text has a long spam-filter history because it can feed words to filters without showing those words to the reader. Senders have used it for neutral terms, keyword stuffing, random words, or copied article fragments intended to change token analysis. Legitimate templates can trigger the same pattern by accident, especially when email builders create tiny preheader text or leave transparent formatting behind.
FONT_INVIS_MSGID combines hidden HTML text with Message-ID and header checks.
FONT_INVIS_MSGID combines hidden HTML text with Message-ID and header checks.
Common legitimate causes
  1. Preheader text: A preview line styled with a one-pixel font or transparent color by the template builder.
  2. Responsive blocks: Mobile or desktop variants that combine display rules with tiny-font or transparent fallback styling.
  3. Editor residue: Copied content that leaves transparent spans or tiny text wrappers.
  4. Generated fields: Merge values placed inside near-zero text by a template component during the final send.
Patterns to remove
  1. Keyword stuffing: Terms hidden in one-pixel text to influence filters or previews.
  2. Transparent copy: Text assigned a transparent color rather than presented to the reader.
  3. Long hidden blocks: Large content sections hidden instead of removed from the final send.
  4. Mismatched previews: Preview text that says something materially different from the visible email.
Risky HTML patternhtml
<span style='font-size:0px;color:transparent'>bonus offer terms</span> <span style='font-size:1px'>extra words not shown to readers</span>
Remove hidden filler and keep preheader text short. A hidden preview line can be legitimate, but its generated HTML still needs testing. Shortening a preheader alone does not remove a matching font style. Remove unnecessary hidden text or revise the markup, then retest the final message.

How to read the Message-ID signal

The Message-ID header is a unique identifier for a message. In this rule, the helper checks only for a host-shaped pattern. It does not compare the Message-ID host with the From domain, DKIM signing domain, or Received path. A provider-managed Message-ID domain can differ from the From domain without being defective. Domain matching is not the positive Message-ID predicate in FONT_INVIS_MSGID.

Signal

What to check

Typical action

Message-ID
Helper pattern, not DNS validity
Fix only actual defects
HTML
Tiny or transparent font
Remove matched text
Received
Preserved relay clues
Test full raw source
MIME and headers
Rule exceptions
Do not manufacture clues
Score
Installed rule set
Check local configuration
Checks that separate the rule hit from other header problems.
Evidence to preserve from the raw messagetext
Message-ID: <unique-token@mail.example.com> Received: from mail.example.com by mx.recipient.net Content-Transfer-Encoding: quoted-printable X-Campaign-ID: campaign-123
A missing or malformed Message-ID is a different failure mode. The related Message-ID bounce page covers that case. For FONT_INVIS_MSGID, begin with the matched body rule and the exact local meta expression.

How to debug FONT_INVIS_MSGID

Keep the process mechanical. Prove which generated HTML triggered the body subtest, confirm the exact rule version, then make the smallest change that removes the signal without damaging the campaign or transactional message.
Apache SpamAssassin command-line report showing FONT_INVIS_MSGID in the rule list.
Apache SpamAssassin command-line report showing FONT_INVIS_MSGID in the rule list.
  1. Save the raw source: Export the complete received message as an .eml file, including all MIME parts and headers. Do not forward it as a substitute for the original source.
  2. Search matched font styles: Decode the HTML MIME part, then look for matched font or font-size values and transparent color.
  3. Check the local rule: Record the SpamAssassin version, active rule file, score set, and any administrator overrides.
  4. Isolate generated blocks: Duplicate the message and remove the preheader or one template block per test until the hit disappears.
  5. Compare relevant headers: Preserve Message-ID, Received, transfer encoding, campaign fields, and thread fields when comparing tests.
  6. Retest the final send: Use the production sender because builders can alter HTML and headers at send time.
  7. Review the total score: Fix the highest-confidence causes and keep enough margin below the recipient's configured threshold.
A live send captures the MIME source and headers generated by the sending system. Suped's email tester checks authentication and sending setup on that delivered sample. Confirm the content-rule result in SpamAssassin's own report.

Email tester

Send a real email to this address. Suped shows a results button when the test is ready.

?/43tests passed
After each retest, check whether the rule disappeared and whether the total score has a safe margin. Do not treat a changed score as proof unless the same SpamAssassin version and configuration processed both samples.
If the rule remains after editing the visible template, search the production-generated source again. A builder can inject preheader markup or tiny fallback text during sending. Change the Message-ID only when a separate header check confirms that its syntax, uniqueness, or generation is actually defective.
Email tester sample report showing total score, email preview, issue summary, and per-section results
Email tester sample report showing total score, email preview, issue summary, and per-section results

How to reproduce the rule locally

On an existing SpamAssassin installation, save the complete message as original.eml and use the same account and configuration as the filtering service. The Apache command-line manual documents these test and debug options.
Record the version and scan a saved messagebash
spamassassin --version spamassassin --lint spamassassin -t -D rules,config \ --cf='bayes_auto_learn 0' \ --cf='add_header all Subtests _SUBTESTS(,)_' \ < original.eml > original-report.eml 2> original-debug.log
Look for FONT_INVIS_MSGID in the report and __FONT_INVIS and __MSGID_OK_HOST in the added X-Spam-Subtests header. Helpers beginning with __ are unscored and normally absent from the standard hit list. The configuration manual documents the subtest header tag.
Repeat with the edited message and different output filenames, keeping the options unchanged. Check X-Spam-Status for the total score and required threshold. Test mode adds a spam-worded report even below the threshold, so read the numeric result. The command disables Bayes auto-learning to avoid training on repeated samples. Keep network-test settings identical because they affect the score set.

What to change in the email

The right fix depends on the evidence in the raw message. Changing a score on your own test system does not change a recipient's filter. A receiving administrator can consider a local override for confirmed false positives, but senders should remove the matched HTML and correct any independently verified header defect.
Template fixes
  1. Remove hidden filler: Delete invisible words that do not help the recipient understand the email.
  2. Shorten preheaders: Use one concise preview line that matches the visible body, then test its generated markup.
  3. Clean copied HTML: Strip unnecessary transparent spans and tiny text wrappers left by an editor.
  4. Avoid split meaning: Do not hide claims, legal qualifiers, or keyword blocks away from readers.
Header checks
  1. Validate the ID: Confirm syntax and uniqueness without assuming this rule proves a defect.
  2. Preserve raw headers: Test the complete Received path and MIME fields produced during the real send.
  3. Check local rules: Use the receiver's active expression and score rather than a generic rule description.
  4. Avoid fake exceptions: Do not add campaign or thread headers solely to bypass the meta rule.
Message-ID hygienetext
Valid shape: Message-ID: <unique-token@mail.example.com> Valid shape: Message-ID: <campaign-id.unique-token@mailer.example.com> Generation defect: unrelated messages reuse <copied-id@mail.example.com> Syntax defect: Message-ID: unique-token@mail.example.com
Message-ID hygiene still matters, but it is separate from the fastest fix for this rule. Use predictable generation and a unique value for each message, while removing hidden content that matched the body test.

Where authentication and reputation fit

SPF, DKIM, and DMARC are not predicates in the published FONT_INVIS_MSGID expression. Passing authentication does not suppress the rule, and failing authentication does not create the hidden-font match. The rule performs content and header checks without querying a DNS blocklist (blacklist). Review independent reputation findings through blocklist monitoring.
Suped's DMARC platform groups authentication reports by sending source. Review legitimate senders that fail DMARC separately from the HTML changes, and use Suped's blocklist monitoring for independent reputation findings.
Suped workflow for this issue
  1. Send a real sample: Use Suped's email tester to inspect authentication on a message sent through production.
  2. Check the domain: Use the domain health checker to review separate DNS and authentication issues.
  3. Fix the direct cause: Confirm the hidden-text fix in a SpamAssassin retest using the receiver's configuration.
  4. Watch for recurrence: Use Suped's DMARC reporting and blocklist alerts to track separate sender issues.

Frequently asked questions

No. The current meta rule uses a helper that matches a host-shaped Message-ID ending. A normal ID can be present when the hidden-font test and the rest of the expression also match.

The raw-body subtest matches specific font-size or font spellings, or transparent color, with an ASCII letter or digit immediately after the HTML tag. It is not a general test of everything an email client hides. Separate SpamAssassin rules cover display:none and visibility:hidden.

Yes, when the generated markup matches the font subtest and the remaining meta-rule conditions also match. A preheader does not trigger the rule merely because an email client hides it. Shortening the text alone does not fix a matching font style.

No. DMARC is not part of this rule expression. Fix the matched HTML directly, then handle authentication findings as separate sender issues.

SpamAssassin versions, score sets, network-test settings, and administrator overrides can assign different values. Some interfaces also display the penalty as a deduction rather than a positive spam score.

A receiving administrator can adjust the score in local.cf after reviewing confirmed false positives. Changing your own testing score does not change recipients' filters, so outbound senders should fix the matched generated HTML.
DMARC monitoring

Start monitoring your DMARC reports today

Suped DMARC platform dashboard
What you'll get with Suped
Real-time DMARC report monitoring and analysis
Automated alerts for authentication failures
Clear recommendations to improve email deliverability
Protection against phishing and domain spoofing