5

The domain & tenant has SPF and DKIM properly configured and DMARC policy set to p=reject. Still, emails spoofed with the domain in the From header aren't rejected, but appear in the Junk Email folder on Office 365. People do check their Junk Email for false positives, and are still reading all the CEO frauds, sextortion letters etc.

This seems a feature instead of a bug, as described in Microsoft's documentation:

How Office 365 handles inbound email that fails DMARC

If the DMARC policy of the sending server is p=reject, EOP marks the message as spam instead of rejecting it. In other words, for inbound email, Office 365 treats p=reject and p=quarantine the same way.

Office 365 is configured like this because some legitimate email may fail DMARC. For example, a message might fail DMARC if it is sent to a mailing list that then relays the message to all list participants. If Office 365 rejected these messages, people could lose legitimate email and have no way to retrieve it. Instead, these messages will still fail DMARC but they will be marked as spam and not rejected.

However, this reasoning has some flaws:

  • DKIM protects legitimate mail; DKIM signed messages do pass with the DMARC policy even if it fails to align with the SPF when forwarded on a mailing list. (Mailing lists should change the envelope sender to pass SPF checks, anyway, so the SPF checks are probably passed, but not aligned.)

  • By implementing p=reject instead of p=quarantine the owner of the domain has stated that the emails should be rejected. Therefore, Microsoft's implementation is against RFC 7489, 6.3:

    p: Requested Mail Receiver policy ...
    
       reject:  The Domain Owner wishes for Mail Receivers to reject
          email that fails the DMARC mechanism check.  Rejection SHOULD
          occur during the SMTP transaction.
    

Is there any setting on Office 365 to alter this behaviour and reject these messages?

  • 1
    I want to take it further: this policy actually trusts the header "From:' again, because they allow users to define exceptions based on them. I did not find your post initially, but now that I did, for reference, my post to the MS tech forum: Office 365 policy negates DMARC because it trusts header-from – Halfgaar Apr 17 at 11:54
  • @Halfgaar: I totally agree with that! How are we supposed to efficiently use DMARC, when a giant has an implementation this bad. – Esa Jokinen Apr 17 at 12:05
5

This can be achieved on an Office 365 tenant by adding a transport rule. An email not passing DMARC tests of a domain having p=reject will have dmarc=fail action=oreject and compauth=fail reason=000 in the Authentication-Results header.

You could catch the dmarc=fail action=oreject:

action Indicates the action taken by the spam filter based on the results of the DMARC check.

  • oreject or o.reject: Stands for override reject. In this case Office 365 uses this action when it receives a message that fails the DMARC check from a domain whose DMARC TXT record has a policy of p=reject. Instead of deleting or rejecting the message, Office 365 marks the message as spam.

Unfortunately, the composite authentication compauth=fail reason=000 is the same for both p=reject and p=quarantine. Using it alone would also affect mails with the less strict policy to only quarantine it. Following the RFC 7489, 6.3 you wouldn't want that.

compauth=fail Message failed explicit authentication (sending domain published records explicitly in DNS) or implicit authentication (sending domain did not publish records in DNS, so Office 365 interpolated the result as if it had published records).

reason=0xx Message failed composite authentication.

  • 000 means the message failed DMARC with an action of reject or quarantine.

To avoid false positives, requiring both would be the best. However, Office 365 transport rules doesn't have an option for "and" conditions: the only suitable option "a message header includes..." can only be used once, and it only has "or"-lists i.e. "includes any of these words". For these reasons I've picked the dmarc=fail action=oreject and use it in the following instructions.


Steps for adding the transport rule:

  1. Go to the Exchange admin center https://outlook.office365.com/ecp/

  2. On mail flow > rules, press the + to add a rule and name it e.g. DMARC reject.

  3. To get the required settings to show, press the "More options..." link below the selection.

  4. On "Apply this rule if..." select "A message header..." and "includes any of there words".

  5. Add the details: 'Authentication-Results' header includes 'dmarc=fail action=oreject'.

    Apply this rule if... A message header includes...

  6. Select the desired action with the setting "Do the following..." and "Block the message..."

    The RFC 7489, 1.3 Rejecting Messages suggests two possibilities:

       o  A "silent discard", wherein the SMTP server returns a 2xy reply
          code implying to the client that delivery (or, at least, relay)
          was successfully completed, but then simply discarding the message
          with no further action.
    

    The equivalent for this would be "Delete the message without notifying anyone."

    Delete the message without notifying anyone.

       o  Full rejection, wherein the SMTP server issues a 5xy reply code as
          an indication to the SMTP client that the transaction failed; the
          SMTP client is then responsible for generating notification that
          delivery failed (see Section 4.2.5 of SMTP RFC 5321).
    

    i.e. "Reject the message with the explanation... rejected by DMARC policy"

    Reject the message with the explanation... rejected by DMARC policy

However, Microsoft Office 365 doesn't support connection-stage rejection, so the latter doesn't exactly respond with an SMTP 5xy reply code, but sends a non-delivery report (NDR) to the envelope sender, with the defined custom message:

NDR: Your message to user@example.com couldn't be delivered.

The technical error on the NDR is 550 5.7.1 TRANSPORT.RULES.RejectMessage; the message was rejected by organization policy and it has the original message headers attached.

| improve this answer | |
  • 1
    Nice write-up! You might want to adjust your detection to using the both the oreject and CompAuth result in the Authentication-Results header. The reject override may be used in other cases while the compauth=fail reason=000 explicitly tells you that the DMARC record found included either p=quarantine or p=reject. You may also want to include reasons 002 and 010. Docs here: docs.microsoft.com/en-us/microsoft-365/security/… – Reinto Feb 23 at 9:34
  • Thanks for the feedback! I've investigated this, and O365 has some limitations that would prevent using both. The compauth=fail reason=000 doesn't separate p=reject from p=quarantine, leaving the dmarc=fail action=oreject more suitable for this use. – Esa Jokinen Feb 23 at 10:47
  • From the documentation I can't find the other use cases for action=oreject, but I adjusted the instructions to use the whole dmarc=fail action=oreject just in case. – Esa Jokinen Feb 23 at 10:48
  • Agreed that currently the only documented reason for the reject override is the default behaviour to quarantine when reject policy is found. This could change over time. Using Powershell you are able to use multiple regex patterns by using the HeaderMatchesPatterns parameter for the set-transportrule cmdlet. It's a bit more advanced, though. Find the docs here: docs.microsoft.com/en-us/powershell/module/exchange/… – Reinto Feb 23 at 11:16
  • That's true. However, I've tried to keep this answer simple enough to be widely usable. Feel free to add an own alternative with the PowerShell approach as an answer. – Esa Jokinen Feb 23 at 11:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.