Microsoft 365

Fix Microsoft 365 email going to Junk by reading SFV, CAT and compauth

Work out why Exchange Online delivered a message to Junk Email from its anti-spam headers, then apply the fix that matches the component that filtered it.

13 min read
On this page

When Microsoft 365 email lands in the Junk Email folder, open the message headers and read three things: the SFV and CAT fields in the X-Forefront-Antispam-Report header, the BCL value in X-Microsoft-Antispam, and the compauth result in Authentication-Results. Together they tell you which component moved the message (content filtering, bulk filtering, spoof and DMARC enforcement, an Advanced Spam Filter setting, a mail flow rule, or the user's own lists), and each component has its own fix. Don't rely on the SCL value: in cloud organizations Microsoft states that it no longer determines the verdict or the action.

Who this is for and what you will have

This guide is for Exchange Online and Microsoft 365 administrators who get tickets like "a supplier's invoices go to Junk" or "the payroll provider's mail is never in the Inbox". It assumes mailboxes in Exchange Online, protected by the built-in anti-spam features (Exchange Online Protection) with or without Microsoft Defender for Office 365. At the end you will have:

  • A repeatable way to read the anti-spam headers and identify which filter acted.
  • The specific fix for each cause, from a false-positive submission to an anti-spam policy change.
  • A way to verify the fix with a new message instead of guessing.

Prerequisites

  • An example of an affected message, ideally still in the user's mailbox, or its network message ID.
  • Exchange Online PowerShell (Connect-ExchangeOnline) with an account that can read anti-spam policies and mailbox junk settings. Changing a user's junk email lists needs the Mail Recipients or User Options role.
  • Access to the Microsoft Defender portal at https://security.microsoft.com. Creating Tenant Allow/Block List entries needs Organization Management or Security Administrator, or the equivalent Defender XDR unified RBAC permission.
  • The Message Header Analyzer at https://mha.azurewebsites.net is optional but makes long headers readable.

Step 1: Get the full message headers

Get the internet headers from the copy that landed in Junk, not from a forwarded copy, because forwarding replaces the headers you need.

  • Outlook for Windows: open the message, select File > Properties, and copy the Internet headers box.
  • Outlook on the web: open the message, select ... (More actions) > View > View message details.
  • Admin: find the message on the Message trace page in the Exchange admin center and view its details.

Paste the headers into the Message Header Analyzer if you want them split into fields. While you have them, note the value of X-MS-Exchange-Organization-Network-Message-Id. You need that GUID if you submit the message to Microsoft later.

Step 2: Read the headers that matter

X-Forefront-Antispam-Report

This header holds field and value pairs separated by semicolons, for example:

X-Forefront-Antispam-Report: CIP:198.51.100.50;CTRY:US;LANG:en;
  SFV:SPM;IPV:NLI;SRV:;H:mail.fabrikam.com;PTR:mail.fabrikam.com;
  CAT:SPM;SFTY:;DIR:INB;

The SFV (spam filtering verdict) field is the primary indicator of what decided the message's fate:

SFV valueWhat it means
SFV:SPMSpam filtering marked the message as spam
SFV:NSPMSpam filtering marked the message as not spam
SFV:BLKSender is in the recipient's Blocked Senders list
SFV:SFESender is in the recipient's Safe Senders list; filtering skipped
SFV:SKASender or domain is on an anti-spam policy's allowed list
SFV:SKBSender or domain is on an anti-spam policy's blocked list
SFV:SKISource IP is on the connection filter IP Allow List (with IPV:CAL)
SFV:SKNA mail flow rule's request to bypass spam filtering was honored
SFV:SKSA mail flow rule (or on-premises Exchange in hybrid) marked it as spam before filtering
SFV:SKQReleased from quarantine

The CAT field names the category of protection that applied, for example SPM (spam), HSPM (high confidence spam), BULK, SPOOF, PHSH (phishing) or HPHSH (high confidence phishing). DIR tells you whether the message was inbound (INB), outbound (OUT) or internal (INT). CIP is the connecting IP address, and SRV:BULK means the message was identified as bulk email.

The SCL field is still stamped, but Microsoft's documentation is explicit that in cloud organizations it doesn't determine whether a message is identified as spam or what action is taken; it exists mainly for on-premises Exchange, including hybrid delivery to the Junk Email folder. Two messages with the same SCL can have different verdicts, so use SFV and CAT for diagnosis.

X-Microsoft-Antispam and X-CustomSpam

X-Microsoft-Antispam contains BCL, the bulk complaint level. A higher BCL means a bulk message is more likely to generate complaints. If BCL meets or exceeds the threshold in the anti-spam policy, the message is treated as bulk.

An X-CustomSpam header appears only when an Advanced Spam Filter (ASF) setting flagged the message, and its value names the setting, for example X-CustomSpam: Web bug.

Authentication-Results

This header records SPF, DKIM and DMARC results and the composite authentication verdict:

Authentication-Results: spf=fail (sender IP is 198.51.100.77)
  smtp.mailfrom=fabrikam.com; dkim=none;
  dmarc=fail action=quarantine header.from=fabrikam.com;
  compauth=fail reason=000

compauth=fail reason=000 means the message failed DMARC and the sender's policy is p=quarantine or p=reject. reason=001 is an implicit failure: the sender's domain has no authentication records or only weak ones (SPF ~all or ?all, or DMARC p=none). reason=130 means a trusted ARC sealer's result overrode a DMARC failure.

Step 3: Match the evidence to the cause

Header evidenceComponent that actedWhere the fix is
SFV:SPM, CAT:SPM or CAT:HSPM, no X-CustomSpamContent filteringFalse-positive submission and allow entry
SFV:SPM with X-CustomSpam: presentAn ASF settingTurn the ASF setting off
SRV:BULK or CAT:BULK, with a BCL valueBulk filteringReview the bulk threshold for the affected users
CAT:SPOOF, compauth=failSpoof intelligence or DMARC enforcementSender authentication, or a spoofed sender allow entry
SFV:BLKUser's Blocked Senders listRemove the entry from the user's list
SFV:SKSMail flow rule that set SCL 5 to 9Find and fix the rule
SFV:NSPM, but the message is in JunkNot the service verdictOutlook client filter, user lists or zero-hour auto purge

Two policy facts explain many surprises. With the default anti-spam policy, messages with the Spam, High confidence spam, Phishing and Bulk verdicts are all moved to the Junk Email folder (MoveToJmf); the Standard and Strict preset policies quarantine some of those instead. And messages that spoof intelligence detects as spoofed are moved to Junk by default in anti-phishing policies, unless the Strict preset applies.

Also check which policy applies to the recipient. Anti-spam policies are evaluated in a fixed order: Strict preset, then Standard preset, then custom policies by priority, then the default policy, and only the first match applies. A setting you changed in a custom policy has no effect on a user who is in a preset policy.

Connect-ExchangeOnline -UserPrincipalName admin@contoso.com
Get-HostedContentFilterRule | Sort-Object Priority |
  Format-Table Name, Priority, State, SentTo, SentToMemberOf, RecipientDomainIs

Step 4: Apply the fix for that cause

Content filtering false positive

Report the message to Microsoft and let the submission create the allow entry:

  1. In the Defender portal, go to Actions & submissions > Submissions (or https://security.microsoft.com/reportsubmission), and on the Emails tab select Submit to Microsoft for analysis.
  2. Enter the network message ID (or upload the .msg or .eml file) and choose at least one affected recipient, so the policy check runs against that recipient.
  3. Under Why are you submitting this message to Microsoft? select I've confirmed it's clean, then Next.
  4. Select Allow this message. Remove allow entry after defaults to 45 days after last used date; the other choices are 1, 7 or 30 days or a specific date up to 30 days ahead.

Allow entries appear on the Tenant Allow/Block Lists page a few moments later. They are created only for the parts of the message the filters found bad. If the sender address wasn't considered malicious, no sender allow entry is created, and the submission result is still useful as feedback.

You can also create sender allow entries directly. These override the bulk, spam, high confidence spam and phishing verdicts, but not high confidence phishing or malware:

New-TenantAllowBlockListItems -ListType Sender -Allow -Entries "billing@fabrikam.com"
Get-TenantAllowBlockListItems -ListType Sender -Allow

Without -ExpirationDate or -RemoveAfter, the entry expires 45 days after it was last used. The number of entries depends on licensing: 500 allow entries without Defender for Office 365, 1,000 with Plan 1 and 5,000 with Plan 2.

Bulk mail

The anti-spam policy's bulk email threshold (BulkThreshold) is 7 in the default policy, 6 in Standard and 5 in Strict; a message at or above it gets the bulk verdict. If a newsletter the business actually wants is caught because its BCL equals the threshold (for example BCL 7 against the default threshold of 7), create a custom anti-spam policy scoped to the users who want it rather than loosening the default policy for everyone:

Get-HostedContentFilterPolicy | Format-Table Name, BulkThreshold, BulkSpamAction, SpamAction
Set-HostedContentFilterPolicy -Identity "Marketing team" -BulkThreshold 8

Remember that a preset policy covering those users wins over any custom policy.

Spoofing and DMARC failures

If CAT:SPOOF and compauth=fail appear, the message failed email authentication. The durable fix is at the sender: SPF that includes the sending service, DKIM signing with the From domain, and DMARC that aligns. When you are the sender (mail from your own domain arriving in another tenant's Junk), set up DKIM signing as described in DKIM CNAME records not found.

If the message passes through a mail gateway or service that modifies it before Microsoft 365, authentication often breaks in transit; ARC trusted sealers and Enhanced Filtering covers that case. For a legitimate third party you can't get fixed quickly, create an allow entry for the spoofed sender and its sending infrastructure. Spoofed sender entries never expire, so review them:

New-TenantAllowBlockListSpoofItems -Identity Default -Action Allow `
  -SpoofedUser billing@fabrikam.com -SendingInfrastructure fabrikam.net -SpoofType External

The sending infrastructure is the domain from the PTR record of the source IP, a verified DKIM domain, or the source IP as a /24 if there's no PTR record.

Advanced Spam Filter settings

Every ASF setting is off by default, and Microsoft no longer recommends enabling them. You also can't report messages that ASF flags as false positives. If X-CustomSpam names a setting, turn it off in the policy that applied:

Get-HostedContentFilterPolicy | Format-Table Identity, MarkAsSpam*, IncreaseScoreWith* -AutoSize
Set-HostedContentFilterPolicy -Identity "Default" -MarkAsSpamWebBugsInHtml Off

The user's own Blocked Senders list

SFV:BLK means the user (or an admin) blocked the sender. Check and remove the entry:

Get-MailboxJunkEmailConfiguration -Identity "user@contoso.com" | Format-List trusted*,contacts*,blocked*
Set-MailboxJunkEmailConfiguration -Identity "user@contoso.com" -BlockedSendersAndDomains @{Remove="fabrikam.com"}

A mail flow rule

SFV:SKS points to a rule that set the SCL to mark messages as spam. List every rule that sets an SCL, and read its conditions against the message:

Get-TransportRule | Where-Object {$_.SetSCL -ne $null} | Format-Table Name, State, SetSCL, Priority

The detailed message trace also shows an AGENTINFO event naming the rule that fired.

The verdict was "not spam" but the message is in Junk

If the header shows SFV:NSPM, the service delivered the message as clean. Check these instead:

  • Outlook Junk Email Filter: when set to Low or High, Outlook applies its own classification after delivery, separately from the Microsoft 365 verdict. Microsoft recommends leaving it at No automatic filtering, which you can enforce with Group Policy.
  • User lists processed by Outlook: Outlook still uses the Safe Senders and Blocked Senders lists to move messages after delivery.
  • Zero-hour auto purge: if ZAP later decides a delivered message is spam or phishing, it moves it to Junk Email for policies whose action is Move message to Junk Email folder.

What not to do

It's tempting to create a mail flow rule that sets SCL to -1 for the sender's domain. Microsoft warns that setting SCL -1 creates significant risk if the conditions aren't carefully scoped, and a rule keyed only on a sender domain also applies to messages that spoof that domain. Such a rule also doesn't bypass malware scanning, and when your MX record points to Microsoft 365 it doesn't deliver high confidence phishing either. If you must use one, combine several conditions, for example sender address plus a specific header value. Use the advanced delivery policy, not a rule, for SecOps mailboxes and phishing simulations.

Similarly, avoid anti-spam policy allowed domains for common providers; attackers can spoof allowed domains. Prefer the Tenant Allow/Block List, whose entries expire and show a last-used date.

Verify the fix

  1. Ask the sender to send a new message; old messages keep their old headers.
  2. Read the new headers. The spam, bulk or spoof verdict you found in step 2 should be gone; a fixed DMARC problem shows compauth=pass.
  3. Confirm the message is in the Inbox for every affected recipient. Tenant Allow/Block List entries should be active within 5 minutes.
  4. On the Tenant Allow/Block Lists page, check the Last used date of the entry you created, so you know it is the thing that made the difference.

Troubleshooting

The allow entry exists but mail still goes to Junk. Check whether the user is in the Standard or Strict preset security policy; allowed sender lists in custom anti-spam policies are ignored for those users, so use the Tenant Allow/Block List instead. Also confirm the verdict isn't malware or high confidence phishing, which allow lists can't override.

Safe Senders entries aren't honored. If the applied policy quarantines the verdict instead of moving it to Junk, domain entries in a user's Safe Senders list aren't honored; individual email address entries are, unless the message is malware or high confidence phishing.

Outlook reports: "Cannot/Unable add to the server Junk E-mail lists. You are over the size allowed on the server." The user's safelist collection exceeded the 510 KB limit. Ask the user to remove old entries; the server-side Junk filter is disabled until the lists are reduced.

Only some recipients see the message in Junk. Different recipients can match different anti-spam policies, and each user has their own lists and Outlook settings. Compare the headers from two recipients.

The sender's own mail from your tenant lands in Junk elsewhere. That's the receiving organization's filter. Check your DKIM, SPF and DMARC first, then ask the recipient's admin for their headers.

Checklist

  • Headers taken from the copy in Junk, not a forward.
  • SFV, CAT, BCL, X-CustomSpam and compauth read; SCL ignored for the diagnosis.
  • Applicable anti-spam policy confirmed, including preset policies.
  • Fix applied at the component that acted: submission and allow entry, bulk threshold, sender authentication or spoof entry, ASF setting, user list, mail flow rule or Outlook client setting.
  • No broad SCL -1 rule added.
  • New test message delivered to the Inbox and its headers checked.

References

Questions people ask

Does the SCL value decide whether Microsoft 365 sends a message to Junk?

No. Microsoft's documentation says the spam confidence level no longer determines the Spam or High confidence spam verdict or the action in cloud organizations. Read the SFV and CAT fields in X-Forefront-Antispam-Report instead; SCL mainly matters for on-premises and hybrid Exchange.

Why is a message in Junk when the header says SFV:NSPM?

SFV:NSPM means the service's spam filtering judged the message not spam. If it still ended up in Junk Email, look at the client side: the Outlook Junk Email Filter set to Low or High uses its own classification, and the user's Blocked Senders list can move mail after delivery. Zero-hour auto purge can also move a delivered message to Junk later.

How do I stop a legitimate sender going to Junk for everyone?

Submit an example to Microsoft from the Submissions page in the Defender portal with "I've confirmed it's clean" and select "Allow this message". That creates an allow entry in the Tenant Allow/Block List, kept by default for 45 days after it was last used. Avoid broad SCL -1 mail flow rules, which Microsoft calls a significant risk.

Can an allow entry override high confidence phishing or malware?

Not one you create directly. Allow entries created on the Tenant Allow/Block List page override bulk, spam, high confidence spam and regular phishing only. Overriding high confidence phishing requires an allow entry created through an admin submission, and mail flow rules can never bypass malware scanning.

Exchange OnlineExchange Online ProtectionMessage headersOutlookDefender for Office 365
  1. Configure ARC trusted sealers and Enhanced Filtering for an email gateway

    Stop SPF, DKIM and DMARC failures on mail that reaches Exchange Online through a third-party gateway by combining Enhanced Filtering for Connectors and ARC.

    Microsoft 36511 min read
  2. Control the new Outlook for Windows rollout with policies and toggles

    The admin controls for new Outlook for Windows: hide the toggle, stop automatic migration, block the app or mailbox access, and migrate on your own schedule before the March 2027 opt-out.

    Microsoft 36513 min read
  3. Fix 550 5.1.8 Access denied, bad outbound sender in Exchange Online

    Why Exchange Online blocks a user with 550 5.1.8, how to secure the account first, and how to remove it from Restricted entities in the Defender portal or with Remove-BlockedSenderAddress.

    Microsoft 36510 min read