skills/content/spam-filter-avoidance/SKILL.md
Avoid triggering spam filters with your email content. Use when emails land in spam, auditing content for filter triggers, checking link patterns, or optimizing HTML structure.
npx skillsauth add chunkydotdev/email-skills spam-filter-avoidanceInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Understand how spam filters evaluate your email and write content that passes cleanly - without tricks.
inbox-placement - the full picture of what determines inbox vs spam (reputation, engagement, authentication, and content)domain-authentication - SPF, DKIM, DMARC setup (filters check authentication before content)sender-reputation - reputation signals that outweigh content in filter decisionstemplate-design - building HTML emails that render correctly and avoid structural triggersemail-compliance - legal requirements like unsubscribe links that also affect filteringModern spam filters are not keyword blocklists. They are multi-signal classifiers that evaluate messages across several dimensions simultaneously. Understanding the architecture matters because it tells you what you can and cannot control at the content level.
When your email arrives at a mailbox provider, it passes through these stages in order:
Content analysis is stage 4 of 6. By the time a filter evaluates your content, it has already formed an opinion based on your reputation and authentication. This is why the same content can land in inbox from one sender and spam from another.
Gmail processes over 15 billion unwanted messages daily using ML models trained on billions of user interactions. These models evaluate:
SpamAssassin (still widely used by corporate mail servers, ISPs, and hosting providers) takes a different approach: rule-based scoring where each matched rule adds points toward a threshold (default 5.0). This means specific patterns have specific, predictable scores.
The practical consequence: you need to satisfy both ML classifiers (Gmail, Outlook) and rule-based systems (SpamAssassin, enterprise filters). ML classifiers are harder to game but more forgiving of individual signals. Rule-based systems are predictable but unforgiving when you trip multiple rules.
The subject line gets disproportionate attention from filters because spammers rely heavily on urgency and deception in subjects.
ALL CAPS subjects. SpamAssassin rule SUBJ_ALL_CAPS adds 1.5+ points. Gmail's classifier also treats all-caps as a negative signal. A subject like LIMITED TIME OFFER trips both systems.
Excessive punctuation. Multiple exclamation marks (!!!), question marks (???), or dollar signs ($$$) are classic spam signals. SpamAssassin has specific rules for these. One exclamation mark is fine. Three is a flag.
Spam trigger phrases in subjects. These phrases in subject lines carry more weight than the same phrases in the body:
| Category | Examples | Why they trigger | |----------|----------|-----------------| | Urgency | "Act now", "Limited time", "Urgent", "Expires today" | Pressure tactics are the most common spam pattern | | Financial | "Free money", "No obligation", "Guaranteed", "Double your income" | Financial fraud is the #1 spam category | | Deceptive | "Re:", "Fwd:" (on non-replies), "You've been selected" | Fake threading and fake personalization | | Medical | "Lose weight", "Miracle cure", "No prescription" | Pharmaceutical spam is heavily targeted |
Misleading Re:/Fwd: prefixes. Adding Re: to a subject that isn't a reply trips the FAKE_REPLY rule in SpamAssassin and is actively penalized by Gmail. Same for Fwd: on messages that aren't forwards. Filters check Message-ID, In-Reply-To, and References headers to verify threading.
The phrases listed below are not absolute blocklist words. A sender with strong reputation can use "free" or "guaranteed" without consequence. But these phrases add negative weight, and when combined with other signals (new domain, low engagement, poor HTML), they push the score over the threshold.
High-risk phrases (carry the most weight across both ML and rule-based systems):
Medium-risk phrases (contribute to score but rarely trigger alone):
The real rule: Density matters more than individual words. One instance of "free" in a 500-word email is noise. Five instances of pressure phrases in a 100-word email is spam. Filters evaluate the ratio of promotional language to total content.
Filters specifically detect attempts to hide content or fool classifiers:
Zero-width characters. Inserting Unicode zero-width spaces (U+200B), zero-width joiners (U+200D), byte order marks (U+FEFF), or soft hyphens (U+00AD) between letters to break up spam words (like "V\u200Biagra") is an old trick that every modern filter detects. These characters are actively flagged and their presence alone is a spam signal.
Invisible text. White text on white background, font-size:0, display:none, or visibility:hidden content is detected by both SpamAssassin (HIDDEN_TEXT rules) and Gmail. Spammers use this to inject "good" text (like news articles) that the recipient can't see but the classifier reads, trying to dilute the spam score. Filters now treat hidden text as a strong negative signal.
HTML comment stuffing. Adding legitimate-looking text inside HTML comments (<!-- buy stocks at ... -->) to influence classifiers. Detected and penalized.
Character substitution. Using Cyrillic characters that look like Latin (e.g., Cyrillic "a" instead of Latin "a") or HTML entities (&#V;iagra) to bypass text matching. Modern filters normalize text before evaluation.
The ratio of visible text to HTML markup matters. An email that is mostly HTML tags with very little readable text looks like it's trying to hide something. Aim for substantial readable text in every email.
Links are the most scrutinized element in email content because they are the primary mechanism for phishing and malware delivery.
Do not use URL shorteners (bit.ly, tinyurl.com, t.co, etc.) in email. They are heavily penalized because:
Use your own domain for all links. If you need click tracking, use a subdomain you own (e.g., track.example.com/click/...) with proper HTTPS.
Too many links signal promotional or phishing email:
SpamAssassin scores increase progressively with link count. The LOTS_OF_MONEY and URI_COUNT family of rules fire at various thresholds.
When the visible text of a link is a URL that doesn't match the actual href, filters treat this as phishing:
<!-- BAD - anchor text says one URL, href goes somewhere else -->
<a href="https://evil.com/steal">https://www.yourbank.com/login</a>
<!-- BAD - "Click here" as sole anchor text -->
<a href="https://example.com/offer">Click here</a>
<!-- GOOD - descriptive, honest anchor text -->
<a href="https://example.com/pricing">View pricing details</a>
<!-- GOOD - matching URL text -->
<a href="https://example.com">https://example.com</a>
Gmail specifically checks for URL-as-anchor-text mismatches and flags them as potential phishing.
Every link in your email is checked against real-time URL blocklists (URIBL, SURBL, Google Safe Browsing). SpamAssassin's URIBL rules carry high scores (1.5-3.6 points each). If any domain in your email appears on these lists, the entire message is penalized.
This means:
All links should use HTTPS. SpamAssassin has rules for HTTP links in email (HTTP_IN_EMAIL), and Gmail treats HTTP links as a minor negative signal. More importantly, some enterprise filters block HTTP links outright as a security policy.
The way your HTML email is constructed tells filters a lot about whether you're a legitimate sender.
The widely cited guideline is 60:40 text-to-image ratio (by area). The practical rules:
SpamAssassin's HTML_IMAGE_RATIO_02 rule fires when text-to-image ratio is below 20%. The rule itself has a low score, but it compounds with other signals.
Broken, malformed, or unnecessarily complex HTML is a spam signal:
<marquee>, <blink>, <embed>, <object>, <form> tags are stripped by email clients and flagged by filters<script> tags, onclick, onload, and other event handlers are always stripped by email clients and are a strong spam signalcharset=UTF-8 in Content-Type)Always send multipart messages with both HTML and plain text parts (multipart/alternative). Missing the plain text version is flagged by SpamAssassin (MIME_HTML_ONLY, scored at 0.7 points) and is a minor negative signal for Gmail.
The plain text part should be a real text rendering of your content, not a copy-paste of the HTML, not blank, and not "View this email in your browser." Recipients on text-only clients or with images disabled see this version.
Missing or malformed headers are easy to detect and consistently penalized.
Every email should include these headers:
| Header | Purpose | What happens without it |
|--------|---------|------------------------|
| From | Sender display name and address | Rejected by most servers |
| To | Recipient address | Some filters flag missing/empty To |
| Date | When the message was sent | SpamAssassin MISSING_DATE rule fires |
| Subject | Message topic | Not technically required but absence is suspicious |
| Message-ID | Unique identifier for this message | MISSING_MID rule fires, some providers reject |
| MIME-Version | Always 1.0 | MISSING_MIME_VERSION fires |
| Content-Type | Media type and charset | Assumed text/plain but absence is a flag |
For any promotional or marketing email, include both headers:
List-Unsubscribe: <https://example.com/unsub?id=abc123>, <mailto:[email protected]?subject=unsubscribe>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
Gmail and Yahoo require one-click unsubscribe for bulk senders (5,000+ messages/day). Microsoft requires it for Outlook.com/Hotmail as of May 2025. Missing these headers on marketing email causes:
The List-Unsubscribe-Post header tells email clients to use POST instead of GET for the unsubscribe request, preventing accidental unsubscribes from security scanners that follow links.
Gmail, Microsoft, and Yahoo run different filtering stacks. What passes at one may fail at another.
Attachments carry risk because they're the primary vector for malware delivery.
These file types are blocked by most enterprise filters and many consumer providers:
.exe, .bat, .cmd, .msi, .scr, .pif, .com.js, .vbs, .wsf, .ps1, .sh.docm, .xlsm, .pptm (macro-enabled Office files).zip, .rar, .7z containing any of the above.jpg, .png, .gif are fine.docx, .xlsx, .pptx (non-macro) are usually accepted.ics files are fineThese are techniques that either never worked, worked briefly, or actively make things worse.
Replacing spam words with synonyms ("F.R.E.E" instead of "free", "vi@gra" instead of "viagra") was defeated by filters over a decade ago. Modern classifiers normalize text, expand character substitutions, and evaluate semantic meaning. Attempted obfuscation is itself a spam signal.
Adding invisible "good" text (news articles, Shakespeare) to dilute spam scores stopped working when filters started detecting hidden content as a strong negative signal. SpamAssassin has specific rules for hidden text. Gmail's classifier treats any hidden content as suspicious.
Putting all your content in a single image to avoid text analysis has never worked reliably. Filters can't read the text, so they assume the worst. Additionally, many email clients block images by default, so the recipient sees a blank email.
Rotating through new domains to avoid reputation damage doesn't work because new domains have no reputation, which is itself a strong spam signal. Warming up a domain takes weeks, and providers track patterns across domains registered by the same entity.
Using Unicode homoglyphs, zero-width characters, or HTML entities to break up spam words is detected by modern filters. The content-sanitizer in production email systems strips these characters before evaluation. Presence of these characters is treated as an evasion attempt.
Test your emails against SpamAssassin before sending. Several tools offer this:
Target a SpamAssassin score below 3.0 (threshold is 5.0, but some servers use lower thresholds like 3.0 or even 2.0).
Send to test accounts at Gmail, Outlook, Yahoo, and any provider your recipients commonly use. Check:
Check the Authentication-Results and X-Spam-Status headers on received messages. They tell you exactly which checks passed, failed, and what scores were assigned.
Before sending, verify:
Obsessing over spam words while ignoring reputation. Content analysis is roughly 10% of the inbox placement decision. If your domain reputation is poor or your complaint rate is above 0.1%, no amount of content optimization will save you. Fix reputation first, then optimize content.
Sending image-only emails for "beautiful design." A single large image with no text is the worst thing you can send from a deliverability perspective. Build your layout in HTML with real text. Use images for supporting visuals, not as the entire message.
Using URL shorteners for "cleaner" links. bit.ly and similar services share their domain across all users, including spammers. Use your own domain for tracking links.
Adding invisible text to "improve" spam scores. This backfired years ago and now actively hurts deliverability. Hidden text, white-on-white text, and zero-width character insertion are all detected and penalized.
Missing the plain text part. Sending HTML-only email without a text/plain alternative trips SpamAssassin's MIME_HTML_ONLY rule and is a minor negative across all providers. Always include a real plain text version.
Not testing across providers. An email that passes Gmail's filter might fail Microsoft's, or vice versa. Test at the providers your recipients actually use, not just the one you use.
Ignoring List-Unsubscribe headers on marketing email. Without the unsubscribe header, recipients who want to opt out will hit the "Report Spam" button instead. Every spam complaint costs you significantly more than an unsubscribe.
Dynamic content without content review. AI agents and template systems that generate email content at runtime can produce phrases or patterns that score poorly in spam classifiers. The sender doesn't see the content before it goes out, so problems compound silently. Implement content linting on outbound messages - check for known spam phrases, validate link patterns, and enforce text-to-image ratios before the message reaches the wire.
data-ai
Choose and configure an email service provider. Use when setting up email for a new project, comparing providers, migrating between providers, or adding failover.
development
Set up SPF, DKIM, and DMARC email authentication. Use when configuring a new sending domain, debugging spam/rejection issues, adding email providers, or preparing for Google/Yahoo/Microsoft bulk sender requirements.
development
Design and send transactional emails. Use when building password resets, receipts, shipping notifications, account alerts, or separating transactional from marketing streams.
development
Build welcome and activation email sequences. Use when designing signup flows, driving users to key actions, converting trials to paid, or reducing early churn.