<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Battle Hardened</title>
    <description>The latest articles on DEV Community by Battle Hardened (@battlehardened).</description>
    <link>https://dev.to/battlehardened</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3963526%2F4c4b1680-c461-4dae-aeef-9b4849ef6a7e.png</url>
      <title>DEV Community: Battle Hardened</title>
      <link>https://dev.to/battlehardened</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/battlehardened"/>
    <language>en</language>
    <item>
      <title>Why Compliance Security and Engineering Security Talk Past Each Other</title>
      <dc:creator>Battle Hardened</dc:creator>
      <pubDate>Thu, 11 Jun 2026 05:21:30 +0000</pubDate>
      <link>https://dev.to/battlehardened/why-compliance-security-and-engineering-security-talk-past-each-other-b96</link>
      <guid>https://dev.to/battlehardened/why-compliance-security-and-engineering-security-talk-past-each-other-b96</guid>
      <description>&lt;p&gt;&lt;em&gt;Why compliance and engineering keep talking past each other, and how to get them working on the same problem&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;There is a conversation that happens in security teams constantly, and it almost never goes anywhere useful.&lt;/p&gt;

&lt;p&gt;A compliance professional raises a finding. An engineer responds with a technical explanation. The compliance professional restates the policy requirement. The engineer explains why the policy doesn't apply in this context. The compliance professional files the finding anyway. The engineer closes the ticket without changing anything meaningful. Both sides walk away frustrated, and the actual risk is unchanged.&lt;/p&gt;

&lt;p&gt;This isn't a people problem. It's a framing problem. Compliance security and engineering security are optimizing for different things, measuring success differently, and often asking completely different questions, even when they're sitting in the same room looking at the same system.&lt;/p&gt;

&lt;p&gt;Understanding why is the first step toward making the conversation productive for everyone involved.&lt;/p&gt;




&lt;h2&gt;
  
  
  Two Frames, One Problem
&lt;/h2&gt;

&lt;p&gt;Compliance security asks: &lt;em&gt;Does this meet the standard?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Engineering security asks: &lt;em&gt;Does the standard actually address the threat?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;These are not the same question.&lt;/strong&gt; The gap between them is where a lot of organizational risk lives, unexamined.&lt;/p&gt;

&lt;p&gt;Compliance exists for good reasons. Regulatory frameworks, audit requirements and industry standards create accountability. They give organizations a common baseline, defensible documentation and a shared vocabulary for talking about risk. Without them, security would be ad hoc, inconsistently applied and impossible to verify from the outside.&lt;/p&gt;

&lt;p&gt;But frameworks are necessarily backward-looking. They codify what has gone wrong before and describe controls that were adequate when they were written. They measure whether a control is &lt;em&gt;present&lt;/em&gt;, not whether it is &lt;em&gt;effective&lt;/em&gt; against the threat your organization actually faces.&lt;/p&gt;

&lt;p&gt;Engineering security works from the other direction. It starts with the system as it actually exists, not as it appears on a diagram, and asks what an attacker could do with it. It follows attack chains to their conclusion. It asks not just "is the control present" but "does the control change the outcome if an adversary is motivated and capable."&lt;/p&gt;

&lt;p&gt;Neither frame is complete without the other. Compliance gives you coverage and accountability. Engineering gives you depth and realism. An application that doesn't fit the standard can still be secure in its own way, but "in its own way" has to be shown, not asserted. Hold that thought; it comes back below.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Metric Is Not the Goal
&lt;/h2&gt;

&lt;p&gt;The clearest symptom of the disconnect is how each group thinks about metrics.&lt;/p&gt;

&lt;p&gt;Compliance tends to measure presence and frequency. Is the control documented? Is the scan running? Was the patch applied within the SLA window? These are measurable, auditable and reportable. They produce the dashboards leadership sees and the evidence packages auditors review.&lt;/p&gt;

&lt;p&gt;Engineering tends to be skeptical of metrics for exactly the reasons compliance values them. A metric tells you whether something happened, not whether it mattered. A missed patching deadline could mean a planned maintenance window, a dependency conflict, or real exposure. The number doesn't say which. Chasing it without context produces a lot of activity and little improvement.&lt;/p&gt;

&lt;p&gt;Metrics aren't useless. They're good for spotting trends, allocating resources and giving stakeholders a summary view. But one data point is noise, and a pattern over time is signal. The mistake is treating noise as signal because the reporting cadence demands an answer. Take for example a report that shows non-compliance with vulnerability management. Working to get details on why a given metric was missed in one month of a monthly metric offers little beyond kneejerk reactions to change the process. The real value is repeated misses and the percentage of those misses over multiple months, or even years and figuring out where &lt;em&gt;those&lt;/em&gt; problems are.&lt;/p&gt;

&lt;p&gt;Completion-rate metrics have the same problem. "X percent of findings remediated" measures activity, not outcome. A team that closes every low-severity informational finding while deferring one critical architectural exposure has a high completion rate and a serious unaddressed risk. The metric rewards closing tickets, not reducing exposure.&lt;/p&gt;

&lt;p&gt;Scanner output makes this worse. Basic scanners flag vulnerabilities by version number, known pattern or configuration check, often without knowing whether the vulnerable code path is reachable from an external input, whether the application uses the affected function, or whether other controls make exploitation impractical. (Some newer tools do reachability analysis, which helps, but it isn't universal.) Many findings are theoretically valid and practically irrelevant. Closing them satisfies the metric without changing what an attacker can do, while the handwritten authentication logic three files over, which no scanner would surface, goes unexamined.&lt;/p&gt;

&lt;p&gt;False positives compound it. When a large share of findings turn out to be invalid, the completion rate stops meaning anything: you're measuring how fast you can close things that shouldn't have been opened. Engineers learn that findings can't be trusted at face value and start treating all of them as noise. Remediation slows, not because anyone is negligent, but because the signal-to-noise ratio is too poor to prioritize. Compliance sees low completion and escalates. Engineering sees an unreliable queue and deprioritizes. Both are responding rationally to their own view, and the number gets chased while the risk goes unmanaged.&lt;/p&gt;




&lt;h2&gt;
  
  
  Both Sides Get It Wrong
&lt;/h2&gt;

&lt;p&gt;It would be easy to read the above as "compliance is box-ticking and engineers know better". That isn't the whole picture, and it isn't fair.&lt;/p&gt;

&lt;p&gt;Engineers are confident, and often right, when they say a finding doesn't apply. But "this doesn't apply" is a claim, and sometimes it's wrong. Imagine an engineer who dismisses a finding about an internal-only service because "nothing can reach it from outside", and a later review of the network configuration shows a forgotten rule exposing it. The standard that flagged it, however clumsily, was doing its job. Engineers can miss exposures they've stopped seeing, because they know the system too well to question it.&lt;/p&gt;

&lt;p&gt;So the fix isn't "trust engineers over the standard". It's that the claim needs evidence the other side can check. That brings us to the part most articles skip.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Missing Mechanism: Documented Risk Acceptance
&lt;/h2&gt;

&lt;p&gt;The opening scene, finding filed and ticket closed with nothing changed, usually isn't an argument that needs winning. It's a missing process.&lt;/p&gt;

&lt;p&gt;Most mature organizations resolve it with a formal exception or risk-acceptance path:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;State why the control doesn't apply or can't be met.&lt;/strong&gt; Not "it's not a real vulnerability", but "the vulnerable function isn't reachable because of X".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name the compensating control.&lt;/strong&gt; What is reducing the risk instead?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assign an owner.&lt;/strong&gt; A named person signs that they accept the residual risk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set a review date.&lt;/strong&gt; Exceptions expire, so "not applicable today" gets re-checked.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This gives the engineer a way to say "this doesn't apply" in a form compliance can accept and an auditor can read. It gives compliance evidence instead of a verbal assurance. And it turns a stalemate into a record: if the reasoning turns out to be wrong, there's a named owner and a trail to learn from.&lt;/p&gt;

&lt;p&gt;Without it, the only options are "comply" or "ignore", and both sides pick whichever suits them.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Code Problem
&lt;/h2&gt;

&lt;p&gt;There's a specific version of this disconnect: security reviewers who can't read code assessing systems built by engineers who don't always think about security.&lt;/p&gt;

&lt;p&gt;Take the common practice of reviewing architecture diagrams. A compliance-trained reviewer can check whether required components are present: firewalls, encryption at rest, access controls. What they often can't see is what's &lt;em&gt;missing&lt;/em&gt; from the diagram that would change the assessment: the authentication check that should be on every endpoint but isn't, the proxy that all cross-region traffic is supposed to go through, the setting that looks right on paper and is subtly wrong in the implementation.&lt;/p&gt;

&lt;p&gt;An engineer reading the same diagram fills those gaps automatically. They know "encrypted at rest" doesn't say whether the keys are managed properly. They know the diagram shows the happy path, not the edge cases where controls break down.&lt;/p&gt;

&lt;p&gt;A hypothetical to make it concrete: a diagram shows traffic encrypted between two services. The reviewer ticks the box. An engineer who has seen the deployment knows one service reaches the other through a debugging endpoint that skips the encrypted path. The diagram was accurate about the design and silent about the behavior.&lt;/p&gt;

&lt;p&gt;The same gap shows up in code review. A scanner finds known vulnerability patterns. A trained engineer finds the ones that don't match a pattern: an authorization check that runs in the wrong order, input validation that handles the documented cases but not the undocumented ones, a library that's safe on its own and unsafe in combination with the rest of the system.&lt;/p&gt;

&lt;p&gt;None of this means compliance professionals should become engineers. It means security teams benefit from having both capabilities, and the two groups need enough shared vocabulary to make their perspectives additive rather than parallel.&lt;/p&gt;




&lt;h2&gt;
  
  
  Isolated Controls vs. Attack Chains
&lt;/h2&gt;

&lt;p&gt;The two frames also differ in how they treat context.&lt;/p&gt;

&lt;p&gt;Compliance tends to evaluate controls one at a time. Is the credential stored securely? Is the connection encrypted? Is the certificate valid? Each is a binary question with a checkable answer.&lt;/p&gt;

&lt;p&gt;Engineering tends to evaluate controls in the context of the full attack chain. What would an attacker need to do before reaching this control? What else have they compromised by then? Does this control change what they can do next?&lt;/p&gt;

&lt;p&gt;That changes the cost-benefit math. A control that looks essential in isolation may be redundant given others already in place. A control that looks minor may be the one chokepoint an entire attack chain depends on. Neither is visible without understanding the system as a whole. Both questions are legitimate, and neither is sufficient alone.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Better Looks Like
&lt;/h2&gt;

&lt;p&gt;The goal isn't to make compliance professionals think like engineers or the reverse. It's to make the conversation between them productive. None of this needs an organizational transformation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start with the threat model.&lt;/strong&gt; Before arguing about whether a control is present or a finding is valid, agree on what you're trying to prevent. "What does an attacker need to do to reach this?" is a question both sides can engage with, and the answer reframes everything around risk rather than compliance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Translate before you respond.&lt;/strong&gt; When a compliance professional is about to say "this doesn't meet the standard", the more useful version is "without this control, an attacker who has achieved X can now do Y." When an engineer is about to say "this isn't a real vulnerability", the more useful version is "this is theoretically valid, but the vulnerable path isn't reachable from external input because of Z." Both cost almost nothing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use the exception process.&lt;/strong&gt; Put the engineer's reasoning in writing, with a compensating control, an owner and a review date. Disagreement then ends in a decision instead of a stalemate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Treat the diagram as a starting point.&lt;/strong&gt; Diagrams show intended design. Assessment has to account for the gap between what was designed and what was built, and between what was built and how it behaves under attack.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Measure trends, and still keep the snapshots.&lt;/strong&gt; One missed metric is noise; three in a row in the same area is a signal. Audits and SLAs will still demand point-in-time evidence, so report both: the snapshot for the auditor, the pattern for leadership.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hold joint reviews on contested findings.&lt;/strong&gt; The most effective thing a security leader can do is put compliance and engineering in the same room on the same finding and require a shared conclusion about whether it's real risk. This doesn't scale to every finding, so reserve it for the high-impact or disputed ones. The translation happens in the room, and both sides leave with a fuller picture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learn enough of the other frame to ask its questions.&lt;/strong&gt; Compliance professionals don't need to read code, but they should be able to ask "is this code path reachable from an external input?" Engineers don't need to know every regulation, but they should understand what a control is trying to prevent and what happens organizationally if it fails.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Shared Goal
&lt;/h2&gt;

&lt;p&gt;Compliance and engineering security aren't opposed. They address the same problem from different angles, with different tools, for different audiences.&lt;/p&gt;

&lt;p&gt;Compliance creates the accountability structures organizations need to function at scale and satisfy outside requirements. Engineering creates the technical understanding that makes those structures meaningful rather than performative.&lt;/p&gt;

&lt;p&gt;The conversation breaks down when either side assumes the other's frame is wrong rather than incomplete. A compliance professional who waves off an engineering concern as "not a policy issue", and an engineer who waves off a requirement as "checkbox theater", are making the same mistake: treating their frame as sufficient.&lt;/p&gt;

&lt;p&gt;The most effective teams have both capabilities and a shared vocabulary for translating between them. That translation is where the real security work happens, not in the dashboard and not in the code, but in the conversation between the people who understand both.&lt;/p&gt;




</description>
      <category>cybersecurity</category>
      <category>developers</category>
      <category>security</category>
    </item>
    <item>
      <title>The Counteroffensive: Automated Spam Reporting with Spamhaus</title>
      <dc:creator>Battle Hardened</dc:creator>
      <pubDate>Thu, 04 Jun 2026 01:03:39 +0000</pubDate>
      <link>https://dev.to/battlehardened/the-counteroffensive-automated-spam-reporting-with-spamhaus-j6e</link>
      <guid>https://dev.to/battlehardened/the-counteroffensive-automated-spam-reporting-with-spamhaus-j6e</guid>
      <description>&lt;p&gt;&lt;em&gt;A practical guide to SPF, DKIM, DMARC and Sieve filtering for anyone who owns a domain&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk4d7qxx3m6bdrbyp9ieh.png" alt="Email Spam Security" width="800" height="450"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The Problem Nobody Fixes
&lt;/h2&gt;

&lt;p&gt;Everyone complains about spam. It clogs inboxes, wastes time, and fools just enough people that it stays wildly profitable. The math works for spammers: send a billion emails, fool 0.01% of the people who get them, and you've got 100,000 victims.&lt;/p&gt;

&lt;p&gt;Here's the uncomfortable part: we have tools that make a real dent in this. They've existed for years, they aren't hard to set up, and most domain owners, including plenty who should know better, still haven't bothered.&lt;/p&gt;

&lt;p&gt;That isn't a technical limitation. It's a collective choice.&lt;/p&gt;

&lt;p&gt;Two different things are going on here, and this article keeps them apart:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stopping people from impersonating your domain.&lt;/strong&gt; That's what SPF, DKIM and DMARC do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cutting down the spam that lands in your inbox.&lt;/strong&gt; That's what filtering does (the Sieve section near the end).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article covers what each tool is, why it works, why so few people use it, and exactly how to set it up. The examples use Cloudflare for DNS, but the records are the same anywhere.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Who this is for: personal domains and small setups with a single outbound mail provider. Big companies with lots of senders have extra complications, and I'll point those out, but the main audience is someone running one domain and one inbox who has no good excuse for weak defaults.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What Authentication Does (and Doesn't Do)
&lt;/h2&gt;

&lt;p&gt;Email authentication is not a spam filter. It does one thing: it proves that mail claiming to come from your domain really did.&lt;/p&gt;

&lt;p&gt;That matters because a huge amount of spam and phishing relies on &lt;em&gt;spoofing&lt;/em&gt;, forging the sender address so the message looks like it came from someone you trust. Authentication shuts that door.&lt;/p&gt;

&lt;p&gt;It doesn't stop a spammer who registers their own domain, sets up authentication properly and sends from there. A perfectly authenticated spam email is still spam. That's the job of content filtering, which we'll get to. And when filtering doesn't catch it, you can &lt;a href="https://dev.to/battlehardened/the-counteroffensive-automated-spam-reporting-with-spamhaus-j6e"&gt;fight back and automatically report spam&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It also doesn't stop &lt;em&gt;look-alike&lt;/em&gt; domains (&lt;code&gt;examp1e.com&lt;/code&gt;). That takes monitoring or buying the obvious look-alikes yourself, and it's outside the scope here.&lt;/p&gt;




&lt;h2&gt;
  
  
  If You Only Read One Section
&lt;/h2&gt;

&lt;p&gt;Three DNS records, plus one habit: &lt;strong&gt;check it works before you turn on enforcement.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Remember the split from above. These records stop other people from forging &lt;em&gt;your&lt;/em&gt; address. They don't reduce the spam &lt;em&gt;you&lt;/em&gt; receive. (The Sieve section does that.) Both are worth doing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Copy-paste defaults
&lt;/h3&gt;

&lt;p&gt;Replace &lt;code&gt;example.com&lt;/code&gt; with your domain. This assumes one outbound mail provider.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Record&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SPF (TXT)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;v=spf1 include:&amp;lt;provider's include&amp;gt; -all&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DKIM (TXT or CNAME)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;selector&amp;gt;._domainkey&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exactly what your provider gives you (use a 2048-bit key if offered)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DMARC (TXT)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;_dmarc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;v=DMARC1; p=reject; sp=reject; adkim=r; aspf=r; rua=mailto:dmarc@example.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Common SPF includes (confirm against your provider's docs, since these change):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;SPF include&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Google Workspace&lt;/td&gt;
&lt;td&gt;&lt;code&gt;include:_spf.google.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft 365&lt;/td&gt;
&lt;td&gt;&lt;code&gt;include:spf.protection.outlook.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Proton Mail&lt;/td&gt;
&lt;td&gt;&lt;code&gt;include:_spf.protonmail.ch&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fastmail&lt;/td&gt;
&lt;td&gt;&lt;code&gt;include:spf.messagingengine.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon SES&lt;/td&gt;
&lt;td&gt;&lt;code&gt;include:amazonses.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A domain can only have one SPF record. If you already have one, merge the includes into it instead of adding a second.&lt;/p&gt;

&lt;h3&gt;
  
  
  Order of operations
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Publish SPF and turn on DKIM signing at your provider.&lt;/li&gt;
&lt;li&gt;Send yourself a message at a Gmail or Outlook account. Open "View Original" and confirm you see &lt;code&gt;spf=pass&lt;/code&gt; and &lt;code&gt;dkim=pass&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Publish DMARC. &lt;strong&gt;Not sure about every service that sends as your domain&lt;/strong&gt; (a scanner, a billing tool, a newsletter)? Start with &lt;code&gt;p=none&lt;/code&gt;, read the reports for two weeks, then move to &lt;code&gt;p=reject&lt;/code&gt;. One provider, and you verified it in step 2? Go straight to &lt;code&gt;p=reject&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Re-check with &lt;a href="https://mail-tester.com" rel="noopener noreferrer"&gt;mail-tester.com&lt;/a&gt; or &lt;a href="https://mxtoolbox.com" rel="noopener noreferrer"&gt;MXToolbox&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  A domain that never sends mail
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SPF:    v=spf1 -all
DMARC:  v=DMARC1; p=reject; sp=reject;
MX:     0 .        (a "null MX": tells senders you accept no mail)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No DKIM is needed, because nothing is being signed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Default inbound filter
&lt;/h3&gt;

&lt;p&gt;If your mail host supports Sieve, use the Junk-first script in the filtering section below, and run it for a week before changing anything to &lt;code&gt;discard&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Three Pillars
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SPF: the guest list
&lt;/h3&gt;

&lt;p&gt;SPF is a list of the servers allowed to send mail for your domain. When a message claims to be from you, the receiving server checks your list. Not on the list, not authorized.&lt;/p&gt;

&lt;p&gt;It lives in a DNS TXT record on your root domain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=spf1 include:_spf.example.com -all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The part that matters is the ending. &lt;code&gt;-all&lt;/code&gt; means "anyone not on the list fails". &lt;code&gt;~all&lt;/code&gt; ("softfail") means "be suspicious, but deliver it anyway", which tells receivers your rule is optional.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For a personal or single-provider domain, aim for &lt;code&gt;-all&lt;/code&gt;.&lt;/strong&gt; Big providers often default to &lt;code&gt;~all&lt;/code&gt; because broken outbound mail generates support tickets, and that's a fair stance while you're still working out what sends as you. But it should be a waypoint, not a destination. If you run one domain out of one inbox, you don't have that excuse.&lt;/p&gt;

&lt;p&gt;The usual objection is that forwarding breaks SPF: when someone forwards your mail, the forwarding server's IP isn't on your list. True, but that's a reason to also set up DKIM and DMARC, not a reason to stay on softfail forever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common SPF mistakes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using &lt;code&gt;~all&lt;/code&gt; instead of &lt;code&gt;-all&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;mx&lt;/code&gt; to authorize senders. It's convenient, but it ties who can &lt;em&gt;send&lt;/em&gt; to where you &lt;em&gt;receive&lt;/em&gt;, so changing your MX records can silently change your SPF.&lt;/li&gt;
&lt;li&gt;Going over the 10-DNS-lookup limit by including too many third parties&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nerd corner: how the three fit together.&lt;/strong&gt; Each one answers a different question:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SPF:&lt;/strong&gt; "Is the server that delivered this allowed to send mail for the domain in the &lt;em&gt;envelope&lt;/em&gt; (bounce) address?" It's about the &lt;em&gt;delivery path&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DKIM:&lt;/strong&gt; "Was this message signed by a domain, and is it unchanged since?" It's about the &lt;em&gt;message itself&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DMARC:&lt;/strong&gt; "Does at least one of those passing checks belong to the same domain as the &lt;code&gt;From:&lt;/code&gt; line the reader sees, and if not, what should happen?" It's about the &lt;em&gt;visible identity&lt;/em&gt; and the &lt;em&gt;policy&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key point: SPF and DKIM can each pass for a domain that has nothing to do with the &lt;code&gt;From:&lt;/code&gt; address. A spammer can pass both on their &lt;em&gt;own&lt;/em&gt; domain and put &lt;em&gt;yours&lt;/em&gt; in the &lt;code&gt;From:&lt;/code&gt; line. Neither check stops that on its own. DMARC does, by requiring that the passing check be &lt;em&gt;aligned&lt;/em&gt; with the From domain.&lt;/p&gt;

&lt;p&gt;Why have both SPF and DKIM? Because they fail in opposite situations. Forwarding breaks SPF (the forwarder's IP isn't on your list) but usually leaves DKIM intact. A mailing list that edits the body breaks DKIM but not SPF. DMARC only needs &lt;em&gt;one&lt;/em&gt; aligned pass, so between them most legitimate mail gets through.&lt;/p&gt;

&lt;p&gt;That also explains &lt;code&gt;-all&lt;/code&gt;. Final handling is always up to the receiver's local policy, and RFC 7489 (section 6.7) points out the catch: rejecting on an SPF failure stops the receiver from ever evaluating DKIM, which might have passed and satisfied DMARC. A receiver that wants DMARC to decide will therefore ignore SPF's verdict, at the cost of accepting the whole message first. Others hard-reject on &lt;code&gt;-all&lt;/code&gt; straight away, which is how forwarded mail can get bounced, and why forwarders that rewrite the envelope sender (SRS) matter. &lt;code&gt;-all&lt;/code&gt; still helps receivers that don't evaluate DMARC, and it's the whole defence for a domain that never sends mail.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  DKIM: the tamper-proof seal
&lt;/h3&gt;

&lt;p&gt;DKIM puts a cryptographic signature on every message you send. The receiver looks up your public key in DNS and checks the signature. If anyone changed the message on the way, the seal breaks.&lt;/p&gt;

&lt;p&gt;Its big advantage is forwarding. SPF fails when mail is forwarded, but the DKIM signature travels &lt;em&gt;with&lt;/em&gt; the message, so it generally still passes. That's what makes a strict DMARC policy workable.&lt;/p&gt;

&lt;p&gt;It isn't a 100% guarantee. Forwarders that rewrite subjects or inject banners into the body will still break the signature. But modern forwarding preserves DKIM far better than old mailing-list software did.&lt;/p&gt;

&lt;p&gt;Your mail provider does the signing. Your only job is to publish the DNS record they give you. Use 2048-bit keys where offered.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nerd corner.&lt;/strong&gt; DKIM is two halves: your server holds a private key and signs outgoing mail, and you publish the matching public key at a selector name like &lt;code&gt;cf2024-1._domainkey.example.com&lt;/code&gt;. Large providers also increasingly use ARC (Authenticated Received Chain), which preserves authentication results across forwarding hops and mailing lists. It doesn't replace DKIM or DMARC. For most personal domains it just works in the background, but the name is worth knowing if you're debugging forwarding.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  DMARC: the policy that ties it together
&lt;/h3&gt;

&lt;p&gt;SPF and DKIM each check something. DMARC is where you tell receivers what to &lt;em&gt;do&lt;/em&gt; when a message fails.&lt;/p&gt;

&lt;p&gt;It also checks &lt;em&gt;alignment&lt;/em&gt;: the domain that passed SPF or DKIM has to match the &lt;code&gt;From:&lt;/code&gt; address people actually see. That closes the loophole where a spammer passes SPF on their own domain while putting yours in the From line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=DMARC1; p=reject; sp=reject; adkim=r; aspf=r;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;p=reject&lt;/code&gt;: ask receivers to reject mail that fails&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sp=reject&lt;/code&gt;: same policy for subdomains&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;adkim=r&lt;/code&gt; / &lt;code&gt;aspf=r&lt;/code&gt;: relaxed alignment, meaning a subdomain of your domain counts as a match&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why &lt;code&gt;p=reject&lt;/code&gt; won't wreck forwarded mail:&lt;/strong&gt; DMARC needs &lt;em&gt;either&lt;/em&gt; SPF &lt;em&gt;or&lt;/em&gt; DKIM to align, not both. Forwarding breaks SPF but not DKIM, so DMARC still passes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The policy ladder:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;p=none&lt;/code&gt;: monitoring only. Fine for a short stretch while you set up.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;p=quarantine&lt;/code&gt;: send failures to spam. A reasonable middle step.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;p=reject&lt;/code&gt;: the goal. Most major receivers honor it; a few apply local overrides.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most domains that publish DMARC at all are sitting on &lt;code&gt;p=none&lt;/code&gt;, which is the equivalent of putting up a "no trespassing" sign without a fence.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nerd corner.&lt;/strong&gt; Relaxed alignment is the ecosystem default and is what you want unless you're sure otherwise. Strict alignment (&lt;code&gt;adkim=s; aspf=s&lt;/code&gt;) is a deliberate hardening step that breaks things when your provider sends through a tracking or bounce subdomain, which email-marketing platforms and Salesforce-style senders commonly do. Only go strict if your provider sends from your exact root domain.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Setting It Up
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Where your provider hands you the values
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Setup Documentation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Google Workspace&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://knowledge.workspace.google.com/admin/security/set-up-dmarc" rel="noopener noreferrer"&gt;Admin Console → Apps → Gmail → Authenticate Email&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Microsoft 365&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://learn.microsoft.com/en-us/defender-office-365/email-authentication-dmarc-configure" rel="noopener noreferrer"&gt;Security Portal → Email Auth Settings&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Proton Mail&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://proton.me/support/anti-spoofing-custom-domain" rel="noopener noreferrer"&gt;Settings → Domain Names → Review&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GoDaddy Email&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.godaddy.com/help/add-spf-dkim-and-dmarc-to-my-domain-for-professional-email-42437" rel="noopener noreferrer"&gt;Email &amp;amp; Office Dashboard → Manage&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Amazon SES&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/ses/latest/dg/send-email-authentication-dkim.html" rel="noopener noreferrer"&gt;SES Console → Identities → Easy DKIM&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cloudflare + any provider&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Add records in DNS dashboard → DNS → Add Record&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For DKIM, copy the string your provider gives you exactly. Don't type it by hand and don't tidy up the tags. Providers differ (Microsoft 365 uses CNAMEs, some add extra tags), and the exact string they give you is the one that works.&lt;/p&gt;

&lt;p&gt;Before you add DMARC, make sure SPF exists, DKIM is signing outbound mail, and you've seen both pass on a real message.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it looks like in Cloudflare
&lt;/h3&gt;

&lt;p&gt;The mail provider doesn't matter here. These records are the same wherever your mail is hosted:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MX&lt;/td&gt;
&lt;td&gt;@&lt;/td&gt;
&lt;td&gt;mail.example.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TXT&lt;/td&gt;
&lt;td&gt;@&lt;/td&gt;
&lt;td&gt;v=spf1 include:_spf.example.com -all&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TXT&lt;/td&gt;
&lt;td&gt;selector._domainkey&lt;/td&gt;
&lt;td&gt;v=DKIM1; h=sha256; k=rsa; p=[key from your provider]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TXT&lt;/td&gt;
&lt;td&gt;_dmarc&lt;/td&gt;
&lt;td&gt;v=DMARC1; p=reject; sp=reject; adkim=r; aspf=r;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  DMARC reports
&lt;/h3&gt;

&lt;p&gt;Add a &lt;code&gt;rua&lt;/code&gt; tag and receivers will email you daily summaries of who's sending as your domain and whether any of it fails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=DMARC1; p=reject; sp=reject; adkim=r; aspf=r; rua=mailto:dmarc@example.com;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reports arrive as zipped XML, which is charitably not user-friendly. Free tools like Postmark's DMARC monitor or Dmarcian turn them into something readable. They're most useful while you're rolling things out; after that, they're noise unless you're watching them.&lt;/p&gt;

&lt;p&gt;There's also a second kind, forensic reports (&lt;code&gt;ruf&lt;/code&gt;), but many receivers have stopped sending them for privacy reasons. Don't worry if they never show up. Focus on the aggregate (&lt;code&gt;rua&lt;/code&gt;) reports.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check that it worked
&lt;/h3&gt;

&lt;p&gt;DNS changes usually take minutes, occasionally a few hours depending on caching. Then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://mxtoolbox.com" rel="noopener noreferrer"&gt;MXToolbox&lt;/a&gt;: checks all three records&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mail-tester.com" rel="noopener noreferrer"&gt;mail-tester.com&lt;/a&gt;: send a test email, get a score&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.dmarcanalyzer.com/spf/checker/" rel="noopener noreferrer"&gt;DMARC Analyzer&lt;/a&gt;: validates SPF specifically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One more step worth doing: send a real email to a personal Gmail or Outlook account and open the raw headers ("View Original" in Gmail, "View Message Source" in Outlook). Confirm &lt;code&gt;dmarc=pass&lt;/code&gt; and that the domains match yours. mail-tester is an isolated test; real alignment problems sometimes only show up in actual delivery.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Changing an existing record&lt;/strong&gt;, for example swapping a &lt;code&gt;~all&lt;/code&gt; SPF for &lt;code&gt;-all&lt;/code&gt;? Lower its TTL to 300 seconds a day or so beforehand, make the change, then raise it again. Otherwise resolvers may keep serving the old value for the old TTL. (A brand-new record has nothing stale cached, so this only applies to edits.)&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Most Domains Don't Do This
&lt;/h2&gt;

&lt;p&gt;It's worth understanding, because the setup genuinely isn't hard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The defaults are wrong.&lt;/strong&gt; Most mail providers generate an SPF record ending in &lt;code&gt;~all&lt;/code&gt;. Most DNS providers never prompt you for DMARC. Most registrars don't mention authentication at all. The easy path leads to a weak setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The coordination excuse is overused.&lt;/strong&gt; "If I enforce strictly I might break forwarded mail, so I'll wait for everyone else." Everyone waits, and the result is collective inaction dressed up as caution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The pain falls on other people.&lt;/strong&gt; If your domain gets spoofed in a phishing campaign, the victims suffer, not you. The cost of doing nothing is pushed onto others, which is exactly why voluntary adoption has been slow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The big players haven't used all their leverage.&lt;/strong&gt; Google and Microsoft handle most of the world's email. Their 2024 requirement that bulk senders use DKIM and DMARC moved more domains into compliance than a decade of documentation. But it stopped at &lt;code&gt;p=none&lt;/code&gt;, monitoring only. Requiring enforcement would change the ecosystem overnight.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A word on Cloudflare.&lt;/strong&gt; They can't safely force strict defaults without breaking legacy setups: scanner-to-email gadgets, forgotten SaaS integrations, automated billing systems. But they could add validation wizards that nudge people off abandoned &lt;code&gt;p=none&lt;/code&gt; policies and warn about broken SPF. That gap is a product decision, not a technical limit. If you use Cloudflare, tell them.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Advanced filtering ahead.&lt;/strong&gt; Everything above is baseline domain security for any domain owner, whatever mail client or provider you use. Everything below is optional, for people whose mail host exposes Sieve scripting. If yours doesn't, or you'd rather not edit server-side scripts, the authentication stack above is enough.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Filtering What Lands in Your Inbox
&lt;/h2&gt;

&lt;p&gt;Authentication protects your &lt;em&gt;outbound&lt;/em&gt; identity. For inbound spam that passes authentication, because the spammer owns a real domain, you need filtering.&lt;/p&gt;

&lt;p&gt;Sieve is a mail-filtering language that runs on the server, before mail reaches any of your devices, so the filtering works whichever client you use. Many hosts support it without advertising it, so check your provider's docs or ask support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start with Junk, not &lt;code&gt;discard&lt;/code&gt;.&lt;/strong&gt; Send suspect messages to Junk with &lt;code&gt;fileinto "Junk"&lt;/code&gt; and run that way for at least a week. Only switch a rule to &lt;code&gt;discard&lt;/code&gt; once it has produced no false positives &lt;em&gt;and&lt;/em&gt; you're sure you'd never want to see what it catches. &lt;code&gt;discard&lt;/code&gt; can't be undone: no copy, no bounce, no recovery. It can silently swallow an invoice from a vendor with broken email setup.&lt;/p&gt;

&lt;p&gt;Here's a practical script. Everything goes to Junk first, which you can recover from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sieve"&gt;&lt;code&gt;&lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"fileinto"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"regex"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;# rule:[[JUNK] Provider spam flag]&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:is&lt;/span&gt; &lt;span class="s2"&gt;"x-junk-flag"&lt;/span&gt; &lt;span class="s2"&gt;"YES"&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fileinto&lt;/span&gt; &lt;span class="s2"&gt;"Junk"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# rule:[[JUNK] Rspamd score &amp;gt;= 6.0]&lt;/span&gt;
&lt;span class="c1"&gt;# The ^ anchor means negative scores (trusted mail) never match.&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:regex&lt;/span&gt; &lt;span class="s2"&gt;"x-rspamd-score"&lt;/span&gt; &lt;span class="s2"&gt;"^[+]?([6-9]|[1-9][0-9]+)&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;."&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fileinto&lt;/span&gt; &lt;span class="s2"&gt;"Junk"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# rule:[[JUNK] Broken DKIM with no passing signature]&lt;/span&gt;
&lt;span class="c1"&gt;# The "not dkim=pass" guard keeps mail that has one failing and one passing&lt;/span&gt;
&lt;span class="c1"&gt;# signature (e.g. mailing lists) out of Junk.&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;allof&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;anyof&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:contains&lt;/span&gt; &lt;span class="s2"&gt;"authentication-results"&lt;/span&gt; &lt;span class="s2"&gt;"dkim=fail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:contains&lt;/span&gt; &lt;span class="s2"&gt;"authentication-results"&lt;/span&gt; &lt;span class="s2"&gt;"dkim=invalid"&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nv"&gt;not&lt;/span&gt; &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:contains&lt;/span&gt; &lt;span class="s2"&gt;"authentication-results"&lt;/span&gt; &lt;span class="s2"&gt;"dkim=pass"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fileinto&lt;/span&gt; &lt;span class="s2"&gt;"Junk"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# OPTIONAL: exempt your own forwarding domains from the next rule.&lt;/span&gt;
&lt;span class="c1"&gt;# Uncomment and replace example.com. SRS-forwarded mail often has&lt;/span&gt;
&lt;span class="c1"&gt;# spf=fail and no DKIM. Only do this if you see it landing in Junk.&lt;/span&gt;
&lt;span class="c1"&gt;# if address :domain :is "from" ["example.com", "example.net"]&lt;/span&gt;
&lt;span class="c1"&gt;# {&lt;/span&gt;
&lt;span class="c1"&gt;#     keep;&lt;/span&gt;
&lt;span class="c1"&gt;#     stop;&lt;/span&gt;
&lt;span class="c1"&gt;# }&lt;/span&gt;

&lt;span class="c1"&gt;# rule:[[JUNK] No DKIM and SPF failed]&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;allof&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:contains&lt;/span&gt; &lt;span class="s2"&gt;"authentication-results"&lt;/span&gt; &lt;span class="s2"&gt;"dkim=none"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:regex&lt;/span&gt; &lt;span class="s2"&gt;"authentication-results"&lt;/span&gt; &lt;span class="s2"&gt;"spf=(fail|softfail|permerror)"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fileinto&lt;/span&gt; &lt;span class="s2"&gt;"Junk"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# rule:[[JUNK] DMARC unknown]&lt;/span&gt;
&lt;span class="c1"&gt;# "unknown" is not a standard RFC 8601 result; it depends on how your host&lt;/span&gt;
&lt;span class="c1"&gt;# writes the header. Check Junk to confirm it catches real spam, or delete it.&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:contains&lt;/span&gt; &lt;span class="s2"&gt;"authentication-results"&lt;/span&gt; &lt;span class="s2"&gt;"dmarc=unknown"&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fileinto&lt;/span&gt; &lt;span class="s2"&gt;"Junk"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three notes on the script:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The DKIM guard.&lt;/strong&gt; A message can carry two signatures, for instance a mailing list that rewrites the body and adds its own. The original fails and the list's passes, so &lt;code&gt;dkim=fail&lt;/code&gt; and &lt;code&gt;dkim=pass&lt;/code&gt; both appear. Without the guard, that legitimate mail goes to Junk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The forwarding exemption.&lt;/strong&gt; If other domains of yours forward into this mailbox, SRS rewriting can produce &lt;code&gt;spf=fail&lt;/code&gt; with no DKIM, which the "No DKIM and SPF failed" rule would junk. Check Junk for your own domains before turning the exemption on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;dmarc=unknown&lt;/code&gt; is host-specific.&lt;/strong&gt; The standard result values are &lt;code&gt;none&lt;/code&gt;, &lt;code&gt;pass&lt;/code&gt;, &lt;code&gt;fail&lt;/code&gt;, &lt;code&gt;policy&lt;/code&gt;, &lt;code&gt;neutral&lt;/code&gt;, &lt;code&gt;temperror&lt;/code&gt; and &lt;code&gt;permerror&lt;/code&gt;. &lt;code&gt;unknown&lt;/code&gt; is a custom string your host may write. It's a weak signal on its own, so keep the rule only if you've seen it catch real spam.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What the DKIM results mean
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;dkim=none&lt;/code&gt;: no signature at all. Combined with an SPF failure, that's a strong spam signal.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dkim=fail&lt;/code&gt;: a signature was there but didn't verify, so the message changed after it was signed. Legitimate causes include old mailing-list software, corporate gateways that append disclaimers, "safe links" URL rewriting and MIME bugs. If you're not on mailing lists or corporate forwarding chains, it's a strong spam signal.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dkim=pass&lt;/code&gt;: the signature checked out. That proves the message wasn't tampered with, but says nothing about whether it's spam.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The spam-score problem
&lt;/h3&gt;

&lt;p&gt;Rspamd (the spam scorer many hosts use) stamps each message with a score in &lt;code&gt;X-Rspamd-Score&lt;/code&gt;. Trusted mail can score &lt;em&gt;negative&lt;/em&gt; (like &lt;code&gt;-2.1&lt;/code&gt;), and Sieve has no clean, universal way to compare decimals and negatives. Here are three ways to write the rule.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tier 1: Regex (precise).&lt;/strong&gt; The script above. The &lt;code&gt;^&lt;/code&gt; anchor means a negative score like &lt;code&gt;-6.5&lt;/code&gt; can never match. The catch is that the &lt;code&gt;regex&lt;/code&gt; extension is optional and not every host supports it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tier 2: Glob patterns (works everywhere).&lt;/strong&gt; No extensions needed, and because &lt;code&gt;:matches&lt;/code&gt; anchors the whole value, a leading &lt;code&gt;-&lt;/code&gt; can never match:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sieve"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:matches&lt;/span&gt; &lt;span class="s2"&gt;"x-rspamd-score"&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"6.*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"7.*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"8.*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"9.*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"1?.*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"2?.*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"3?.*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fileinto&lt;/span&gt; &lt;span class="s2"&gt;"Junk"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This covers scores up to 39.x, which is plenty. &lt;strong&gt;Don't&lt;/strong&gt; write it as &lt;code&gt;:contains "6."&lt;/code&gt;: that matches &lt;code&gt;-6.5&lt;/code&gt;, so your most trusted mail gets caught.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tier 3: Relational comparison (only with a guard).&lt;/strong&gt; This is the tidiest to read, but there's a trap. Under &lt;code&gt;i;ascii-numeric&lt;/code&gt; (RFC 4790), a value that doesn't start with a digit, like &lt;code&gt;-1.5&lt;/code&gt;, counts as larger than any number. An unguarded &lt;code&gt;ge "6"&lt;/code&gt; therefore &lt;em&gt;matches&lt;/em&gt; negative scores, the opposite of what you want. Guard it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sieve"&gt;&lt;code&gt;&lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"fileinto"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"relational"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"comparator-i;ascii-numeric"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;allof&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;not&lt;/span&gt; &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:matches&lt;/span&gt; &lt;span class="s2"&gt;"x-rspamd-score"&lt;/span&gt; &lt;span class="s2"&gt;"-*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:value&lt;/span&gt; &lt;span class="s2"&gt;"ge"&lt;/span&gt; &lt;span class="o"&gt;:comparator&lt;/span&gt; &lt;span class="s2"&gt;"i;ascii-numeric"&lt;/span&gt; &lt;span class="s2"&gt;"x-rspamd-score"&lt;/span&gt; &lt;span class="s2"&gt;"6"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fileinto&lt;/span&gt; &lt;span class="s2"&gt;"Junk"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt; try Tier 1; if your host doesn't support &lt;code&gt;regex&lt;/code&gt;, use Tier 2; prefer Tier 2 over Tier 3.&lt;/p&gt;

&lt;h3&gt;
  
  
  Junk or discard?
&lt;/h3&gt;

&lt;p&gt;Both are silent. Neither tells the sender anything, so neither "confirms your address exists". The real difference is whether you can recover a mistake: Junk lets you rescue a false positive, &lt;code&gt;discard&lt;/code&gt; doesn't. (Bouncing is the one option that actually hurts people, since spam usually forges the return address and the bounce lands in an innocent person's inbox. Never bounce.) Plenty of people never need to go beyond Junk.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two things to check before you trust any of this
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Header formats vary.&lt;/strong&gt; These rules match the wording of &lt;code&gt;Authentication-Results&lt;/code&gt; as it appears from one particular host. Providers format it differently, and some rewrite or strip upstream results. Send yourself a few test messages and look at the raw headers your provider produces. Your patterns need to match what &lt;em&gt;your&lt;/em&gt; host writes, not what the RFC says it should.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thresholds vary.&lt;/strong&gt; A score of 6.0 is a reasonable starting point, but scores differ between systems. Watch for false positives and adjust.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Sieve won't catch
&lt;/h3&gt;

&lt;p&gt;Sophisticated spam from authenticated domains with low scores: mail that passes every technical check because the sender set things up correctly and keeps the content just under detection thresholds. Apple Mail, Outlook and tools like SpamSieve use content analysis and learning to catch more of it. Server-side Sieve and client-side filtering work best as two layers.&lt;/p&gt;




&lt;h2&gt;
  
  
  When Softer Settings Are Legitimate
&lt;/h2&gt;

&lt;p&gt;This article pushes for the strongest settings: SPF &lt;code&gt;-all&lt;/code&gt;, &lt;code&gt;p=reject&lt;/code&gt;, DKIM signing. For a home user or hobbyist on a single provider, those are right and there's no good reason to hold back.&lt;/p&gt;

&lt;p&gt;But there are real situations where something softer is a genuine constraint rather than neglect:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mailing lists.&lt;/strong&gt; Software like Mailman often rewrites headers or strips DKIM signatures when it redistributes mail, which breaks DMARC alignment. Organizations running busy lists sometimes stay on &lt;code&gt;p=quarantine&lt;/code&gt; or &lt;code&gt;p=none&lt;/code&gt; so list delivery doesn't break.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Complicated forwarding.&lt;/strong&gt; If a third-party service forwards your domain's mail onward, its IP isn't in your SPF record and DKIM may not survive the trip. That needs careful handling before you enforce strictly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Big organizations with many senders.&lt;/strong&gt; A company using Salesforce, Marketo, a ticketing system, a payment processor and an HR platform, all sending as the same domain, has to audit every one of them before enforcing. Going to &lt;code&gt;p=reject&lt;/code&gt; first means silently dropping legitimate business mail. &lt;code&gt;p=none&lt;/code&gt; during the audit is correct. The trouble is that the audit often never ends.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Domains mid-migration.&lt;/strong&gt; &lt;code&gt;p=none&lt;/code&gt; is the right starting point when you genuinely don't know every sender yet. The ladder (none, quarantine, reject) exists for a reason. The mistake is treating &lt;code&gt;p=none&lt;/code&gt; as the destination.&lt;/p&gt;

&lt;p&gt;None of this applies to a home user or hobbyist with one domain and one provider. If you send through exactly one service and your reports look clean, there's no technical justification for softfail SPF or &lt;code&gt;p=none&lt;/code&gt; DMARC. The exceptions are real, but they belong to a kind of organizational complexity most readers of this article don't have.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Ceiling
&lt;/h2&gt;

&lt;p&gt;With SPF &lt;code&gt;-all&lt;/code&gt;, DKIM, DMARC &lt;code&gt;p=reject&lt;/code&gt; and Sieve filtering in place, you've reached the ceiling of what email authentication can do. You'll still get some spam: the sophisticated kind, from properly authenticated domains with low scores. That's not a failure of your setup. It's the unsolved remainder of a problem the whole industry is still working on.&lt;/p&gt;

&lt;p&gt;What you've done:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Made straightforward spoofing of your domain fail at receivers that honor DMARC&lt;/li&gt;
&lt;li&gt;Filtered most inbound spam out of your inbox&lt;/li&gt;
&lt;li&gt;Configured your domain better than most commercial organizations bother to&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tools exist. The setup takes an afternoon. And most people still won't do it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want to fight back? &lt;a href="https://dev.to/battlehardened/the-counteroffensive-automated-spam-reporting-with-spamhaus-j6e"&gt;The Counteroffensive: Automated Spam Reporting with Spamhaus&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>automation</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Why Your Email is an Open Door for Spammers -- And How to Lock It</title>
      <dc:creator>Battle Hardened</dc:creator>
      <pubDate>Tue, 02 Jun 2026 12:00:00 +0000</pubDate>
      <link>https://dev.to/battlehardened/why-your-email-is-an-open-door-for-spammers-and-how-to-lock-it-1k1n</link>
      <guid>https://dev.to/battlehardened/why-your-email-is-an-open-door-for-spammers-and-how-to-lock-it-1k1n</guid>
      <description>&lt;p&gt;&lt;em&gt;A practical guide to SPF, DKIM, DMARC and Sieve filtering for anyone who owns a domain&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk4d7qxx3m6bdrbyp9ieh.png" alt="Email Spam Security" width="800" height="450"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The Problem Nobody Fixes
&lt;/h2&gt;

&lt;p&gt;Everyone complains about spam. It clogs inboxes, wastes time, and fools just enough people that it stays wildly profitable. The math works for spammers: send a billion emails, fool 0.01% of the people who get them, and you've got 100,000 victims.&lt;/p&gt;

&lt;p&gt;Here's the uncomfortable part: we have tools that make a real dent in this. They've existed for years, they aren't hard to set up, and most domain owners, including plenty who should know better, still haven't bothered.&lt;/p&gt;

&lt;p&gt;That isn't a technical limitation. It's a collective choice.&lt;/p&gt;

&lt;p&gt;Two different things are going on here, and this article keeps them apart:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stopping people from impersonating your domain.&lt;/strong&gt; That's what SPF, DKIM and DMARC do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cutting down the spam that lands in your inbox.&lt;/strong&gt; That's what filtering does (the Sieve section near the end).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article covers what each tool is, why it works, why so few people use it, and exactly how to set it up. The examples use Cloudflare for DNS, but the records are the same anywhere.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Who this is for: personal domains and small setups with a single outbound mail provider. Big companies with lots of senders have extra complications, and I'll point those out, but the main audience is someone running one domain and one inbox who has no good excuse for weak defaults.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What Authentication Does (and Doesn't Do)
&lt;/h2&gt;

&lt;p&gt;Email authentication is not a spam filter. It does one thing: it proves that mail claiming to come from your domain really did.&lt;/p&gt;

&lt;p&gt;That matters because a huge amount of spam and phishing relies on &lt;em&gt;spoofing&lt;/em&gt;, forging the sender address so the message looks like it came from someone you trust. Authentication shuts that door.&lt;/p&gt;

&lt;p&gt;It doesn't stop a spammer who registers their own domain, sets up authentication properly and sends from there. A perfectly authenticated spam email is still spam. That's the job of content filtering, which we'll get to. And when filtering doesn't catch it, you can &lt;a href="https://dev.to/battlehardened/the-counteroffensive-automated-spam-reporting-with-spamhaus-j6e"&gt;fight back and automatically report spam&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It also doesn't stop &lt;em&gt;look-alike&lt;/em&gt; domains (&lt;code&gt;examp1e.com&lt;/code&gt;). That takes monitoring or buying the obvious look-alikes yourself, and it's outside the scope here.&lt;/p&gt;




&lt;h2&gt;
  
  
  If You Only Read One Section
&lt;/h2&gt;

&lt;p&gt;Three DNS records, plus one habit: &lt;strong&gt;check it works before you turn on enforcement.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Remember the split from above. These records stop other people from forging &lt;em&gt;your&lt;/em&gt; address. They don't reduce the spam &lt;em&gt;you&lt;/em&gt; receive. (The Sieve section does that.) Both are worth doing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Copy-paste defaults
&lt;/h3&gt;

&lt;p&gt;Replace &lt;code&gt;example.com&lt;/code&gt; with your domain. This assumes one outbound mail provider.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Record&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SPF (TXT)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;v=spf1 include:&amp;lt;provider's include&amp;gt; -all&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DKIM (TXT or CNAME)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;selector&amp;gt;._domainkey&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exactly what your provider gives you (use a 2048-bit key if offered)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DMARC (TXT)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;_dmarc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;v=DMARC1; p=reject; sp=reject; adkim=r; aspf=r; rua=mailto:dmarc@example.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Common SPF includes (confirm against your provider's docs, since these change):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;SPF include&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Google Workspace&lt;/td&gt;
&lt;td&gt;&lt;code&gt;include:_spf.google.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft 365&lt;/td&gt;
&lt;td&gt;&lt;code&gt;include:spf.protection.outlook.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Proton Mail&lt;/td&gt;
&lt;td&gt;&lt;code&gt;include:_spf.protonmail.ch&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fastmail&lt;/td&gt;
&lt;td&gt;&lt;code&gt;include:spf.messagingengine.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon SES&lt;/td&gt;
&lt;td&gt;&lt;code&gt;include:amazonses.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A domain can only have one SPF record. If you already have one, merge the includes into it instead of adding a second.&lt;/p&gt;

&lt;h3&gt;
  
  
  Order of operations
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Publish SPF and turn on DKIM signing at your provider.&lt;/li&gt;
&lt;li&gt;Send yourself a message at a Gmail or Outlook account. Open "View Original" and confirm you see &lt;code&gt;spf=pass&lt;/code&gt; and &lt;code&gt;dkim=pass&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Publish DMARC. &lt;strong&gt;Not sure about every service that sends as your domain&lt;/strong&gt; (a scanner, a billing tool, a newsletter)? Start with &lt;code&gt;p=none&lt;/code&gt;, read the reports for two weeks, then move to &lt;code&gt;p=reject&lt;/code&gt;. One provider, and you verified it in step 2? Go straight to &lt;code&gt;p=reject&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Re-check with &lt;a href="https://mail-tester.com" rel="noopener noreferrer"&gt;mail-tester.com&lt;/a&gt; or &lt;a href="https://mxtoolbox.com" rel="noopener noreferrer"&gt;MXToolbox&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  A domain that never sends mail
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SPF:    v=spf1 -all
DMARC:  v=DMARC1; p=reject; sp=reject;
MX:     0 .        (a "null MX": tells senders you accept no mail)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No DKIM is needed, because nothing is being signed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Default inbound filter
&lt;/h3&gt;

&lt;p&gt;If your mail host supports Sieve, use the Junk-first script in the filtering section below, and run it for a week before changing anything to &lt;code&gt;discard&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Three Pillars
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SPF: the guest list
&lt;/h3&gt;

&lt;p&gt;SPF is a list of the servers allowed to send mail for your domain. When a message claims to be from you, the receiving server checks your list. Not on the list, not authorized.&lt;/p&gt;

&lt;p&gt;It lives in a DNS TXT record on your root domain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=spf1 include:_spf.example.com -all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The part that matters is the ending. &lt;code&gt;-all&lt;/code&gt; means "anyone not on the list fails". &lt;code&gt;~all&lt;/code&gt; ("softfail") means "be suspicious, but deliver it anyway", which tells receivers your rule is optional.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For a personal or single-provider domain, aim for &lt;code&gt;-all&lt;/code&gt;.&lt;/strong&gt; Big providers often default to &lt;code&gt;~all&lt;/code&gt; because broken outbound mail generates support tickets, and that's a fair stance while you're still working out what sends as you. But it should be a waypoint, not a destination. If you run one domain out of one inbox, you don't have that excuse.&lt;/p&gt;

&lt;p&gt;The usual objection is that forwarding breaks SPF: when someone forwards your mail, the forwarding server's IP isn't on your list. True, but that's a reason to also set up DKIM and DMARC, not a reason to stay on softfail forever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common SPF mistakes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using &lt;code&gt;~all&lt;/code&gt; instead of &lt;code&gt;-all&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;mx&lt;/code&gt; to authorize senders. It's convenient, but it ties who can &lt;em&gt;send&lt;/em&gt; to where you &lt;em&gt;receive&lt;/em&gt;, so changing your MX records can silently change your SPF.&lt;/li&gt;
&lt;li&gt;Going over the 10-DNS-lookup limit by including too many third parties&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nerd corner: how the three fit together.&lt;/strong&gt; Each one answers a different question:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SPF:&lt;/strong&gt; "Is the server that delivered this allowed to send mail for the domain in the &lt;em&gt;envelope&lt;/em&gt; (bounce) address?" It's about the &lt;em&gt;delivery path&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DKIM:&lt;/strong&gt; "Was this message signed by a domain, and is it unchanged since?" It's about the &lt;em&gt;message itself&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DMARC:&lt;/strong&gt; "Does at least one of those passing checks belong to the same domain as the &lt;code&gt;From:&lt;/code&gt; line the reader sees, and if not, what should happen?" It's about the &lt;em&gt;visible identity&lt;/em&gt; and the &lt;em&gt;policy&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key point: SPF and DKIM can each pass for a domain that has nothing to do with the &lt;code&gt;From:&lt;/code&gt; address. A spammer can pass both on their &lt;em&gt;own&lt;/em&gt; domain and put &lt;em&gt;yours&lt;/em&gt; in the &lt;code&gt;From:&lt;/code&gt; line. Neither check stops that on its own. DMARC does, by requiring that the passing check be &lt;em&gt;aligned&lt;/em&gt; with the From domain.&lt;/p&gt;

&lt;p&gt;Why have both SPF and DKIM? Because they fail in opposite situations. Forwarding breaks SPF (the forwarder's IP isn't on your list) but usually leaves DKIM intact. A mailing list that edits the body breaks DKIM but not SPF. DMARC only needs &lt;em&gt;one&lt;/em&gt; aligned pass, so between them most legitimate mail gets through.&lt;/p&gt;

&lt;p&gt;That also explains &lt;code&gt;-all&lt;/code&gt;. Once DMARC is enforcing, an SPF failure alone isn't what decides the outcome, and the RFC advises receivers not to reject on SPF alone when a DMARC policy exists. &lt;code&gt;-all&lt;/code&gt; still helps receivers that don't evaluate DMARC, and it's the whole defence for a domain that never sends mail. A receiver that hard-rejects on &lt;code&gt;-all&lt;/code&gt; &lt;em&gt;before&lt;/em&gt; checking DKIM can still bounce forwarded mail, which is why forwarders that rewrite the envelope sender (SRS) matter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  DKIM: the tamper-proof seal
&lt;/h3&gt;

&lt;p&gt;DKIM puts a cryptographic signature on every message you send. The receiver looks up your public key in DNS and checks the signature. If anyone changed the message on the way, the seal breaks.&lt;/p&gt;

&lt;p&gt;Its big advantage is forwarding. SPF fails when mail is forwarded, but the DKIM signature travels &lt;em&gt;with&lt;/em&gt; the message, so it generally still passes. That's what makes a strict DMARC policy workable.&lt;/p&gt;

&lt;p&gt;It isn't a 100% guarantee. Forwarders that rewrite subjects or inject banners into the body will still break the signature. But modern forwarding preserves DKIM far better than old mailing-list software did.&lt;/p&gt;

&lt;p&gt;Your mail provider does the signing. Your only job is to publish the DNS record they give you. Use 2048-bit keys where offered.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nerd corner.&lt;/strong&gt; DKIM is two halves: your server holds a private key and signs outgoing mail, and you publish the matching public key at a selector name like &lt;code&gt;cf2024-1._domainkey.example.com&lt;/code&gt;. Large providers also increasingly use ARC (Authenticated Received Chain), which preserves authentication results across forwarding hops and mailing lists. It doesn't replace DKIM or DMARC. For most personal domains it just works in the background, but the name is worth knowing if you're debugging forwarding.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  DMARC: the policy that ties it together
&lt;/h3&gt;

&lt;p&gt;SPF and DKIM each check something. DMARC is where you tell receivers what to &lt;em&gt;do&lt;/em&gt; when a message fails.&lt;/p&gt;

&lt;p&gt;It also checks &lt;em&gt;alignment&lt;/em&gt;: the domain that passed SPF or DKIM has to match the &lt;code&gt;From:&lt;/code&gt; address people actually see. That closes the loophole where a spammer passes SPF on their own domain while putting yours in the From line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=DMARC1; p=reject; sp=reject; adkim=r; aspf=r;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;p=reject&lt;/code&gt;: ask receivers to reject mail that fails&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sp=reject&lt;/code&gt;: same policy for subdomains&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;adkim=r&lt;/code&gt; / &lt;code&gt;aspf=r&lt;/code&gt;: relaxed alignment, meaning a subdomain of your domain counts as a match&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why &lt;code&gt;p=reject&lt;/code&gt; won't wreck forwarded mail:&lt;/strong&gt; DMARC needs &lt;em&gt;either&lt;/em&gt; SPF &lt;em&gt;or&lt;/em&gt; DKIM to align, not both. Forwarding breaks SPF but not DKIM, so DMARC still passes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The policy ladder:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;p=none&lt;/code&gt;: monitoring only. Fine for a short stretch while you set up.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;p=quarantine&lt;/code&gt;: send failures to spam. A reasonable middle step.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;p=reject&lt;/code&gt;: the goal. Most major receivers honor it; a few apply local overrides.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most domains that publish DMARC at all are sitting on &lt;code&gt;p=none&lt;/code&gt;, which is the equivalent of putting up a "no trespassing" sign without a fence.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nerd corner.&lt;/strong&gt; Relaxed alignment is the ecosystem default and is what you want unless you're sure otherwise. Strict alignment (&lt;code&gt;adkim=s; aspf=s&lt;/code&gt;) is a deliberate hardening step that breaks things when your provider sends through a tracking or bounce subdomain, which email-marketing platforms and Salesforce-style senders commonly do. Only go strict if your provider sends from your exact root domain.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Setting It Up
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Where your provider hands you the values
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Setup Documentation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Google Workspace&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://knowledge.workspace.google.com/admin/security/set-up-dmarc" rel="noopener noreferrer"&gt;Admin Console → Apps → Gmail → Authenticate Email&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Microsoft 365&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://learn.microsoft.com/en-us/defender-office-365/email-authentication-dmarc-configure" rel="noopener noreferrer"&gt;Security Portal → Email Auth Settings&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Proton Mail&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://proton.me/support/anti-spoofing-custom-domain" rel="noopener noreferrer"&gt;Settings → Domain Names → Review&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GoDaddy Email&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.godaddy.com/help/add-spf-dkim-and-dmarc-to-my-domain-for-professional-email-42437" rel="noopener noreferrer"&gt;Email &amp;amp; Office Dashboard → Manage&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Amazon SES&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/ses/latest/dg/send-email-authentication-dkim.html" rel="noopener noreferrer"&gt;SES Console → Identities → Easy DKIM&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cloudflare + any provider&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Add records in DNS dashboard → DNS → Add Record&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For DKIM, copy the string your provider gives you exactly. Don't type it by hand and don't tidy up the tags. Providers differ (Microsoft 365 uses CNAMEs, some add extra tags), and the exact string they give you is the one that works.&lt;/p&gt;

&lt;p&gt;Before you add DMARC, make sure SPF exists, DKIM is signing outbound mail, and you've seen both pass on a real message.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it looks like in Cloudflare
&lt;/h3&gt;

&lt;p&gt;The mail provider doesn't matter here. These records are the same wherever your mail is hosted:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MX&lt;/td&gt;
&lt;td&gt;@&lt;/td&gt;
&lt;td&gt;mail.example.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TXT&lt;/td&gt;
&lt;td&gt;@&lt;/td&gt;
&lt;td&gt;v=spf1 include:_spf.example.com -all&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TXT&lt;/td&gt;
&lt;td&gt;selector._domainkey&lt;/td&gt;
&lt;td&gt;v=DKIM1; h=sha256; k=rsa; p=[key from your provider]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TXT&lt;/td&gt;
&lt;td&gt;_dmarc&lt;/td&gt;
&lt;td&gt;v=DMARC1; p=reject; sp=reject; adkim=r; aspf=r;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  DMARC reports
&lt;/h3&gt;

&lt;p&gt;Add a &lt;code&gt;rua&lt;/code&gt; tag and receivers will email you daily summaries of who's sending as your domain and whether any of it fails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=DMARC1; p=reject; sp=reject; adkim=r; aspf=r; rua=mailto:dmarc@example.com;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reports arrive as zipped XML, which is charitably not user-friendly. Free tools like Postmark's DMARC monitor or Dmarcian turn them into something readable. They're most useful while you're rolling things out; after that, they're noise unless you're watching them.&lt;/p&gt;

&lt;p&gt;There's also a second kind, forensic reports (&lt;code&gt;ruf&lt;/code&gt;), but many receivers have stopped sending them for privacy reasons. Don't worry if they never show up. Focus on the aggregate (&lt;code&gt;rua&lt;/code&gt;) reports.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check that it worked
&lt;/h3&gt;

&lt;p&gt;DNS changes usually take minutes, occasionally a few hours depending on caching. Then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://mxtoolbox.com" rel="noopener noreferrer"&gt;MXToolbox&lt;/a&gt;: checks all three records&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mail-tester.com" rel="noopener noreferrer"&gt;mail-tester.com&lt;/a&gt;: send a test email, get a score&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.dmarcanalyzer.com/spf/checker/" rel="noopener noreferrer"&gt;DMARC Analyzer&lt;/a&gt;: validates SPF specifically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One more step worth doing: send a real email to a personal Gmail or Outlook account and open the raw headers ("View Original" in Gmail, "View Message Source" in Outlook). Confirm &lt;code&gt;dmarc=pass&lt;/code&gt; and that the domains match yours. mail-tester is an isolated test; real alignment problems sometimes only show up in actual delivery.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Changing an existing record&lt;/strong&gt;, for example swapping a &lt;code&gt;~all&lt;/code&gt; SPF for &lt;code&gt;-all&lt;/code&gt;? Lower its TTL to 300 seconds a day or so beforehand, make the change, then raise it again. Otherwise resolvers may keep serving the old value for the old TTL. (A brand-new record has nothing stale cached, so this only applies to edits.)&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Most Domains Don't Do This
&lt;/h2&gt;

&lt;p&gt;It's worth understanding, because the setup genuinely isn't hard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The defaults are wrong.&lt;/strong&gt; Most mail providers generate an SPF record ending in &lt;code&gt;~all&lt;/code&gt;. Most DNS providers never prompt you for DMARC. Most registrars don't mention authentication at all. The easy path leads to a weak setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The coordination excuse is overused.&lt;/strong&gt; "If I enforce strictly I might break forwarded mail, so I'll wait for everyone else." Everyone waits, and the result is collective inaction dressed up as caution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The pain falls on other people.&lt;/strong&gt; If your domain gets spoofed in a phishing campaign, the victims suffer, not you. The cost of doing nothing is pushed onto others, which is exactly why voluntary adoption has been slow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The big players haven't used all their leverage.&lt;/strong&gt; Google and Microsoft handle most of the world's email. Their 2024 requirement that bulk senders use DKIM and DMARC moved more domains into compliance than a decade of documentation. But it stopped at &lt;code&gt;p=none&lt;/code&gt;, monitoring only. Requiring enforcement would change the ecosystem overnight.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A word on Cloudflare.&lt;/strong&gt; They can't safely force strict defaults without breaking legacy setups: scanner-to-email gadgets, forgotten SaaS integrations, automated billing systems. But they could add validation wizards that nudge people off abandoned &lt;code&gt;p=none&lt;/code&gt; policies and warn about broken SPF. That gap is a product decision, not a technical limit. If you use Cloudflare, tell them.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Advanced filtering ahead.&lt;/strong&gt; Everything above is baseline domain security for any domain owner, whatever mail client or provider you use. Everything below is optional, for people whose mail host exposes Sieve scripting. If yours doesn't, or you'd rather not edit server-side scripts, the authentication stack above is enough.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Filtering What Lands in Your Inbox
&lt;/h2&gt;

&lt;p&gt;Authentication protects your &lt;em&gt;outbound&lt;/em&gt; identity. For inbound spam that passes authentication, because the spammer owns a real domain, you need filtering.&lt;/p&gt;

&lt;p&gt;Sieve is a mail-filtering language that runs on the server, before mail reaches any of your devices, so the filtering works whichever client you use. Many hosts support it without advertising it, so check your provider's docs or ask support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start with Junk, not &lt;code&gt;discard&lt;/code&gt;.&lt;/strong&gt; Send suspect messages to Junk with &lt;code&gt;fileinto "Junk"&lt;/code&gt; and run that way for at least a week. Only switch a rule to &lt;code&gt;discard&lt;/code&gt; once it has produced no false positives &lt;em&gt;and&lt;/em&gt; you're sure you'd never want to see what it catches. &lt;code&gt;discard&lt;/code&gt; can't be undone: no copy, no bounce, no recovery. It can silently swallow an invoice from a vendor with broken email setup.&lt;/p&gt;

&lt;p&gt;Here's a practical script. Everything goes to Junk first, which you can recover from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sieve"&gt;&lt;code&gt;&lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"fileinto"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"regex"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;# rule:[[JUNK] Provider spam flag]&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:is&lt;/span&gt; &lt;span class="s2"&gt;"x-junk-flag"&lt;/span&gt; &lt;span class="s2"&gt;"YES"&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fileinto&lt;/span&gt; &lt;span class="s2"&gt;"Junk"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# rule:[[JUNK] Rspamd score &amp;gt;= 6.0]&lt;/span&gt;
&lt;span class="c1"&gt;# The ^ anchor means negative scores (trusted mail) never match.&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:regex&lt;/span&gt; &lt;span class="s2"&gt;"x-rspamd-score"&lt;/span&gt; &lt;span class="s2"&gt;"^[+]?([6-9]|[1-9][0-9]+)&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;."&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fileinto&lt;/span&gt; &lt;span class="s2"&gt;"Junk"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# rule:[[JUNK] Broken DKIM with no passing signature]&lt;/span&gt;
&lt;span class="c1"&gt;# The "not dkim=pass" guard keeps mail that has one failing and one passing&lt;/span&gt;
&lt;span class="c1"&gt;# signature (e.g. mailing lists) out of Junk.&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;allof&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;anyof&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:contains&lt;/span&gt; &lt;span class="s2"&gt;"authentication-results"&lt;/span&gt; &lt;span class="s2"&gt;"dkim=fail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:contains&lt;/span&gt; &lt;span class="s2"&gt;"authentication-results"&lt;/span&gt; &lt;span class="s2"&gt;"dkim=invalid"&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nv"&gt;not&lt;/span&gt; &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:contains&lt;/span&gt; &lt;span class="s2"&gt;"authentication-results"&lt;/span&gt; &lt;span class="s2"&gt;"dkim=pass"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fileinto&lt;/span&gt; &lt;span class="s2"&gt;"Junk"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# OPTIONAL: exempt your own forwarding domains from the next rule.&lt;/span&gt;
&lt;span class="c1"&gt;# Uncomment and replace example.com. SRS-forwarded mail often has&lt;/span&gt;
&lt;span class="c1"&gt;# spf=fail and no DKIM. Only do this if you see it landing in Junk.&lt;/span&gt;
&lt;span class="c1"&gt;# if address :domain :is "from" ["example.com", "example.net"]&lt;/span&gt;
&lt;span class="c1"&gt;# {&lt;/span&gt;
&lt;span class="c1"&gt;#     keep;&lt;/span&gt;
&lt;span class="c1"&gt;#     stop;&lt;/span&gt;
&lt;span class="c1"&gt;# }&lt;/span&gt;

&lt;span class="c1"&gt;# rule:[[JUNK] No DKIM and SPF failed]&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;allof&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:contains&lt;/span&gt; &lt;span class="s2"&gt;"authentication-results"&lt;/span&gt; &lt;span class="s2"&gt;"dkim=none"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:regex&lt;/span&gt; &lt;span class="s2"&gt;"authentication-results"&lt;/span&gt; &lt;span class="s2"&gt;"spf=(fail|softfail|permerror)"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fileinto&lt;/span&gt; &lt;span class="s2"&gt;"Junk"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# rule:[[JUNK] DMARC unknown]&lt;/span&gt;
&lt;span class="c1"&gt;# "unknown" is not a standard RFC 8601 result; it depends on how your host&lt;/span&gt;
&lt;span class="c1"&gt;# writes the header. Check Junk to confirm it catches real spam, or delete it.&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:contains&lt;/span&gt; &lt;span class="s2"&gt;"authentication-results"&lt;/span&gt; &lt;span class="s2"&gt;"dmarc=unknown"&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fileinto&lt;/span&gt; &lt;span class="s2"&gt;"Junk"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three notes on the script:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The DKIM guard.&lt;/strong&gt; A message can carry two signatures, for instance a mailing list that rewrites the body and adds its own. The original fails and the list's passes, so &lt;code&gt;dkim=fail&lt;/code&gt; and &lt;code&gt;dkim=pass&lt;/code&gt; both appear. Without the guard, that legitimate mail goes to Junk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The forwarding exemption.&lt;/strong&gt; If other domains of yours forward into this mailbox, SRS rewriting can produce &lt;code&gt;spf=fail&lt;/code&gt; with no DKIM, which the "No DKIM and SPF failed" rule would junk. Check Junk for your own domains before turning the exemption on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;dmarc=unknown&lt;/code&gt; is host-specific.&lt;/strong&gt; The standard result values are &lt;code&gt;none&lt;/code&gt;, &lt;code&gt;pass&lt;/code&gt;, &lt;code&gt;fail&lt;/code&gt;, &lt;code&gt;policy&lt;/code&gt;, &lt;code&gt;neutral&lt;/code&gt;, &lt;code&gt;temperror&lt;/code&gt; and &lt;code&gt;permerror&lt;/code&gt;. &lt;code&gt;unknown&lt;/code&gt; is a custom string your host may write. It's a weak signal on its own, so keep the rule only if you've seen it catch real spam.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What the DKIM results mean
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;dkim=none&lt;/code&gt;: no signature at all. Combined with an SPF failure, that's a strong spam signal.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dkim=fail&lt;/code&gt;: a signature was there but didn't verify, so the message changed after it was signed. Legitimate causes include old mailing-list software, corporate gateways that append disclaimers, "safe links" URL rewriting and MIME bugs. If you're not on mailing lists or corporate forwarding chains, it's a strong spam signal.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dkim=pass&lt;/code&gt;: the signature checked out. That proves the message wasn't tampered with, but says nothing about whether it's spam.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The spam-score problem
&lt;/h3&gt;

&lt;p&gt;Rspamd (the spam scorer many hosts use) stamps each message with a score in &lt;code&gt;X-Rspamd-Score&lt;/code&gt;. Trusted mail can score &lt;em&gt;negative&lt;/em&gt; (like &lt;code&gt;-2.1&lt;/code&gt;), and Sieve has no clean, universal way to compare decimals and negatives. Here are three ways to write the rule.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tier 1: Regex (precise).&lt;/strong&gt; The script above. The &lt;code&gt;^&lt;/code&gt; anchor means a negative score like &lt;code&gt;-6.5&lt;/code&gt; can never match. The catch is that the &lt;code&gt;regex&lt;/code&gt; extension is optional and not every host supports it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tier 2: Glob patterns (works everywhere).&lt;/strong&gt; No extensions needed, and because &lt;code&gt;:matches&lt;/code&gt; anchors the whole value, a leading &lt;code&gt;-&lt;/code&gt; can never match:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sieve"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:matches&lt;/span&gt; &lt;span class="s2"&gt;"x-rspamd-score"&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"6.*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"7.*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"8.*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"9.*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"1?.*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"2?.*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"3?.*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fileinto&lt;/span&gt; &lt;span class="s2"&gt;"Junk"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This covers scores up to 39.x, which is plenty. &lt;strong&gt;Don't&lt;/strong&gt; write it as &lt;code&gt;:contains "6."&lt;/code&gt;: that matches &lt;code&gt;-6.5&lt;/code&gt;, so your most trusted mail gets caught.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tier 3: Relational comparison (only with a guard).&lt;/strong&gt; This is the tidiest to read, but there's a trap. Under &lt;code&gt;i;ascii-numeric&lt;/code&gt; (RFC 4790), a value that doesn't start with a digit, like &lt;code&gt;-1.5&lt;/code&gt;, counts as larger than any number. An unguarded &lt;code&gt;ge "6"&lt;/code&gt; therefore &lt;em&gt;matches&lt;/em&gt; negative scores, the opposite of what you want. Guard it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sieve"&gt;&lt;code&gt;&lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"fileinto"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"relational"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"comparator-i;ascii-numeric"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;allof&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;not&lt;/span&gt; &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:matches&lt;/span&gt; &lt;span class="s2"&gt;"x-rspamd-score"&lt;/span&gt; &lt;span class="s2"&gt;"-*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;header&lt;/span&gt; &lt;span class="o"&gt;:value&lt;/span&gt; &lt;span class="s2"&gt;"ge"&lt;/span&gt; &lt;span class="o"&gt;:comparator&lt;/span&gt; &lt;span class="s2"&gt;"i;ascii-numeric"&lt;/span&gt; &lt;span class="s2"&gt;"x-rspamd-score"&lt;/span&gt; &lt;span class="s2"&gt;"6"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fileinto&lt;/span&gt; &lt;span class="s2"&gt;"Junk"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt; try Tier 1; if your host doesn't support &lt;code&gt;regex&lt;/code&gt;, use Tier 2; prefer Tier 2 over Tier 3.&lt;/p&gt;

&lt;h3&gt;
  
  
  Junk or discard?
&lt;/h3&gt;

&lt;p&gt;Both are silent. Neither tells the sender anything, so neither "confirms your address exists". The real difference is whether you can recover a mistake: Junk lets you rescue a false positive, &lt;code&gt;discard&lt;/code&gt; doesn't. (Bouncing is the one option that actually hurts people, since spam usually forges the return address and the bounce lands in an innocent person's inbox. Never bounce.) Plenty of people never need to go beyond Junk.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two things to check before you trust any of this
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Header formats vary.&lt;/strong&gt; These rules match the wording of &lt;code&gt;Authentication-Results&lt;/code&gt; as it appears from one particular host. Providers format it differently, and some rewrite or strip upstream results. Send yourself a few test messages and look at the raw headers your provider produces. Your patterns need to match what &lt;em&gt;your&lt;/em&gt; host writes, not what the RFC says it should.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thresholds vary.&lt;/strong&gt; A score of 6.0 is a reasonable starting point, but scores differ between systems. Watch for false positives and adjust.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Sieve won't catch
&lt;/h3&gt;

&lt;p&gt;Sophisticated spam from authenticated domains with low scores: mail that passes every technical check because the sender set things up correctly and keeps the content just under detection thresholds. Apple Mail, Outlook and tools like SpamSieve use content analysis and learning to catch more of it. Server-side Sieve and client-side filtering work best as two layers.&lt;/p&gt;




&lt;h2&gt;
  
  
  When Softer Settings Are Legitimate
&lt;/h2&gt;

&lt;p&gt;This article pushes for the strongest settings: SPF &lt;code&gt;-all&lt;/code&gt;, &lt;code&gt;p=reject&lt;/code&gt;, DKIM signing. For a home user or hobbyist on a single provider, those are right and there's no good reason to hold back.&lt;/p&gt;

&lt;p&gt;But there are real situations where something softer is a genuine constraint rather than neglect:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mailing lists.&lt;/strong&gt; Software like Mailman often rewrites headers or strips DKIM signatures when it redistributes mail, which breaks DMARC alignment. Organizations running busy lists sometimes stay on &lt;code&gt;p=quarantine&lt;/code&gt; or &lt;code&gt;p=none&lt;/code&gt; so list delivery doesn't break.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Complicated forwarding.&lt;/strong&gt; If a third-party service forwards your domain's mail onward, its IP isn't in your SPF record and DKIM may not survive the trip. That needs careful handling before you enforce strictly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Big organizations with many senders.&lt;/strong&gt; A company using Salesforce, Marketo, a ticketing system, a payment processor and an HR platform, all sending as the same domain, has to audit every one of them before enforcing. Going to &lt;code&gt;p=reject&lt;/code&gt; first means silently dropping legitimate business mail. &lt;code&gt;p=none&lt;/code&gt; during the audit is correct. The trouble is that the audit often never ends.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Domains mid-migration.&lt;/strong&gt; &lt;code&gt;p=none&lt;/code&gt; is the right starting point when you genuinely don't know every sender yet. The ladder (none, quarantine, reject) exists for a reason. The mistake is treating &lt;code&gt;p=none&lt;/code&gt; as the destination.&lt;/p&gt;

&lt;p&gt;None of this applies to a home user or hobbyist with one domain and one provider. If you send through exactly one service and your reports look clean, there's no technical justification for softfail SPF or &lt;code&gt;p=none&lt;/code&gt; DMARC. The exceptions are real, but they belong to a kind of organizational complexity most readers of this article don't have.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Ceiling
&lt;/h2&gt;

&lt;p&gt;With SPF &lt;code&gt;-all&lt;/code&gt;, DKIM, DMARC &lt;code&gt;p=reject&lt;/code&gt; and Sieve filtering in place, you've reached the ceiling of what email authentication can do. You'll still get some spam: the sophisticated kind, from properly authenticated domains with low scores. That's not a failure of your setup. It's the unsolved remainder of a problem the whole industry is still working on.&lt;/p&gt;

&lt;p&gt;What you've done:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Made straightforward spoofing of your domain fail at receivers that honor DMARC&lt;/li&gt;
&lt;li&gt;Filtered most inbound spam out of your inbox&lt;/li&gt;
&lt;li&gt;Configured your domain better than most commercial organizations bother to&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I applied this configuration to a real personal domain in a single afternoon. The filtering rules, not the DNS records, are what cut inbound spam: roughly 160 fewer messages a day reached the inbox, and that only counts what got as far as my server. What still gets through is the sophisticated, fully authenticated kind.&lt;/p&gt;

&lt;p&gt;The tools exist. The setup takes an afternoon. And most people still won't do it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want to fight back? &lt;a href="https://dev.to/battlehardened/the-counteroffensive-automated-spam-reporting-with-spamhaus-j6e"&gt;The Counteroffensive: Automated Spam Reporting with Spamhaus&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>howto</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
