DKIM/SPF/DMARC Verification and Authentication in Exchange Server - Tutorial

DKIM, SPF and DMARC mechanisms are used to validate a domain name identity that is associated with an email message. Verifying DKIM, SPF and DMARC records of inbound email is very helpful to stop spam or spoofing email message.

In this tutorial, I will introduce how to verify and authenticate DKIM signature, SPF record and DMARC record of inbound email messages in Exchange Server 2007/2010/2013/2016/2019 by transport agent.

How DKIM works?

DKIM combines of a public key cryptography and a DNS to provide credible domain-level authentication for email.

When an email claims to originate from a certain domain, DKIM provides a mechanism by which the recipient system can credibly determine that the email did in fact originate from a person or system authorized to send email for that domain.

How DKIM works?

How SPF works?

Sender Policy Framework (SPF) is a simple email-validation system designed to detect email spoofing by providing a mechanism to allow receiving email servers to check that incoming mail from a domain comes from a host authorized by that domain’s administrators based on sender IP address.

How SPF works?

How DMARC works?

Domain-based Message Authentication, Reporting and Conformance or DMARC is a method of email authentication, which is a way to mitigate email abuse. It expands on two existing mechanisms, the well-known Sender Policy Framework (SPF) and DomainKeys Identified Mail (DKIM), coordinating their results on the alignment of the domain in the From: header field, which is often visible to end users.

How DMARC works

Enable DKIM/SPF/DMARC for Outbound email

In this tutorial, we only focus on DKIM/SPF/DMARC verification and authentication.

To enable DKIM/SPF/DMARC for outbound email message in Exchange Server, please refer to the following tutorial:

Install DKIM Plugin in Exchange Server 2007/2010/2013/2016/2019

To enable DKIM/SPF/DMARC verification in Exchange 2007/2010/2013/2016/2019, you should download the DKIM Installer and install it on your server at first.

Note

Exchange Server Role

If you installed Exchange Server 2007/2010/2013/2016/2019 on multiple servers, you don’t have to install DKIM plugin on every server.

  • If there is Exchange Edge Transport Server Role installed, you just need to install DKIM plugin on this server.
  • If there is no Exchange Edge Transport Server Role installed, you just need to install DKIM plugin on every Exchange Hub Transport Server Role.

Note

Exchange 2019 on Server Core

If you need to install DKIM for Exchange 2019, Desktop Experience (GUI) for Windows 2019 is required.

Double click installer file and the installation will be executed automatically. Installer requires Exchange server to be installed. If no Exchange server detected in your operation system, Setup will be aborted.

Important

After the installation is complete, I strongly suggest that you go to Control Panel -> Administrative Tools -> Services, and check if “Microsoft Exchange Transport Service” and “Microsoft Exchange Mail Submission Service” are running, if those service are not running, please start it.

Enable Inbound Transport Agent

By default, DKIM plugin only enables outbound DKIM agent after installation is completed, so you need to enable DKIM inbound transport agent manually.

Open Exchange Management Shell and input:

enable-transportagent "EA Dkim Inbound Agent"
get-transportagent
Enable DKIM/SPF/DMARC inbound agent in Exchange Server.

You can see EA Dkim Inbound Agent is enabled now, you need to restart “Microsoft Exchange Transport Service” in Control Panel -> Administrative Tools -> Services to take effect.

Or you can restart “Microsoft Exchange Transport Service” in Exchange Management Shell directly:

Restart-Service "MSExchangeTransport"

Important

Every time after you executed installation or upgrade, you need to enable inbound transport agent and restart “Microsoft Transport Service” again.

Disable Inbound Transport Agent

You can disable this agent temporally in case you don’t want to use it anymore.

disable-transportagent "EA Dkim Inbound Agent"

Configuration File and First Test

You can find the configuration file in installation path\DkimInboundAgent.dll.config, the default installation path is C:\Program Files (x86)\EAExchDomainKeys. It is in XML format, you can use notepad or other text editor to edit it.

Enable DKIM/SPF/DMARC inbound agent in Exchange Server.

Note

Every time after you changed configuration file, you don’t have to restart “Microsoft Transport Service” again

Here is the default content of configuration file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
    <section name="spfResultToReject"  type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    <section name="ignoredGatewayIPAddressesForSpfCheck"  type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    <section name="ignoredGatewayNameForSpfCheck"  type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    <section name="ignoreSpfResultDomains" type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

    <section name="dkimResultToReject" type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    <section name="ignoreBodyHashErrorDomains" type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    <section name="ignoreDkimResultDomains" type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

    <section name="dmarcResultToReject" type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    <section name="ignoreDmarcResultDomains" type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

    <section name="blockedIPAddresses" type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    <section name="blockedSenderOrHeloDomain" type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

    <section name="trustedIPAddresses" type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    <section name="trustedSenderOrDomain" type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</configSections>

<spfResultToReject>
    <!--
    <add key="fail" value="550 5.7.1 your message from [%source_ip%] is against our SPF policy (fail)" />
    <add key="softfail" value="550 5.7.1 your message from [%source_ip%] is against our SPF policy (softfail)" />
    <add key="none" value="550 5.7.1 your message from [%source_ip%] is against our SPF policy (none)" />
    <add key="neutral" value="550 5.7.1 your message from [%source_ip%] is against our SPF policy (neutral)" />
    <add key="temperror" value="451 4.4.3 your message from [%source_ip%] encountered a temporal error with SPF verification (temperror)" />
    <add key="permerror" value="550 5.7.1 your message from [%source_ip%] encountered a permanent error with SPF verification (permerror)" />
    -->
</spfResultToReject>

<!--
    ignoredGatewayIPAddressesForSpfCheck:

    If your Exchange server is behind of a gateway/MTA,
    the SPF check will be incorrect due to original IP address is hidden by gateway or MTA.

    You can add your gateway/MTA IP address to skip the gateway IP/domain to detect original IP address/helo domain from message headers.

    CIDR syntax is supported in IP address.
    -->
<ignoredGatewayIPAddressesForSpfCheck>
    <!--
    <add key="192.168.0.8" value="ignore"/>
    -->
</ignoredGatewayIPAddressesForSpfCheck>


<!--
    ignoredGatewayNameForSpfCheck:

    If your Exchange server is behind of a gateway/MTA,
    the SPF check will be incorrect due to original IP address/helo domain is hidden by gateway or MTA.

    You can add your gateway/MTA name to skip the gateway IP/domain to detect original IP address/helo domain from message headers.

    You can use regular expression like this "/^emailarchitect\.(net|com)$/"

    "/^emailarchitect\.(net|com)$/" matches "emailarchitect.net" and "emailarchitect.com"

    "/.?emailarchitect\.net$/" matches "*.emailarchitect.net" and "emailarchitect.net"
    -->
<ignoredGatewayNameForSpfCheck>
    <!--
    <add key="dispatch.gateway.net" value="ignore"/>
    -->
</ignoredGatewayNameForSpfCheck>

<!--
    ignoreSpfResultDomains does not take effect to the following domains even the result matches spfResultToReject

    You can use regular expression like this "/^emailarchitect\.(net|com)$/"

    "/^emailarchitect\.(net|com)$/" matches "emailarchitect.net" and "emailarchitect.com"

    "/.?emailarchitect\.net$/" matches "*.emailarchitect.net" and "emailarchitect.net"
    -->
<ignoreSpfResultDomains>
    <!--
    <add key="emailarchitect.net" value="ignore"/>
    -->
</ignoreSpfResultDomains>


<dkimResultToReject>
    <!--
    <add key="fail" value="550 5.7.1 your message from [%header_from%] is against our DKIM policy (fail)" />
    <add key="none" value="550 5.7.1 your message from [%header_from%] is against our DKIM policy (none)" />
    <add key="neutral" value="550 5.7.1 your message from [%header_from%] is against our DKIM policy (neutral)" />
    <add key="temperror" value="451 4.4.3 your message from [%header_from%] encountered a temporal error with DKIM verification (temperror)" />
    <add key="permerror" value="550 5.7.1 your message from [%header_from%] encountered a permanent error with DKIM verification (permerror)" />
    -->
</dkimResultToReject>

<!--
    ignoreBodyHashErrorDomains:

    If the sender or signer domain is in the ignoreBodyHashErrorDomains list, body hash error with DKIM verification is ignored, only the signature is verified.

    you can use regular expression like this "/^emailarchitect\.(net|com)$/"

    "/^emailarchitect\.(net|com)$/" matches "emailarchitect.net" and "emailarchitect.com"

    "/.?emailarchitect\.net$/" matches "*.emailarchitect.net" and "emailarchitect.net"
    -->
<ignoreBodyHashErrorDomains>
    <!--
    <add key="/.?onmicrosoft.com$/" value="ignore"/>
    -->
</ignoreBodyHashErrorDomains>


<!--
    ignoreDkimResultDomains does not take effect to the following domains even the result matches dkimResultToReject

    You can use regular expression like this "/^emailarchitect\.(net|com)$/"

    "/^emailarchitect\.(net|com)$/" matches "emailarchitect.net" and "emailarchitect.com"

    "/.?emailarchitect\.net$/" matches "*.emailarchitect.net" and "emailarchitect.net"
    -->
<ignoreDkimResultDomains>
    <!--
    <add key="emailarchitect.net" value="ignore"/>
    -->
</ignoreDkimResultDomains>


<dmarcResultToReject>
    <!--
    <add key="fail" value="550 5.7.1 your message from [%header_from%] is against our DMARC policy (fail)" />
    <add key="none" value="550 5.7.1 your message from [%header_from%] is against our DMARC policy (none)" />
    <add key="temperror" value="451 4.4.3 your message from [%header_from%] encountered a temporal error with DMARC verification (temperror)" />
    <add key="permerror" value="550 5.7.1 your message from [%header_from%] encountered a permanent error with DMARC verification (permerror)" />
    -->
</dmarcResultToReject>


<!--
    ignoreDmarcResultDomains does not take effect to the following domains even the result matches dmarcResultToReject

    you can use regular expression like this "/^emailarchitect\.(net|com)$/"

    "/^emailarchitect\.(net|com)$/" matches "emailarchitect.net" and "emailarchitect.com"

    "/.?emailarchitect\.net$/" matches "*.emailarchitect.net" and "emailarchitect.net"
    -->
<ignoreDmarcResultDomains>
    <!--
    <add key="emailarchitect.net" value="ignore"/>
    -->
</ignoreDmarcResultDomains>


<!--
blockedIPAddresses:

The email from the following IP address(es) will be rejected directly regardless of SPF/DKIM result.
CIDR syntax is supported in IP address.
    -->
<blockedIPAddresses>
    <!--
    <add key="127.0.0.2" value="550 5.7.1 your message from [%source_ip%] is in our black list." />
    <add key="192.168.0.0/24" value="550 5.7.1 your message from [%source_ip%] is in our black list." />
    -->
</blockedIPAddresses>

<!--
blockedSenderOrHeloDomain
The email from (SMTP MAIL FROM or HELO DOMAIN) the following address(es)/domain(s) will be rejected directly regardless of SPF/DKIM result.
-->
<blockedSenderOrHeloDomain>
    <!--
        You can use regular expression like this: "/^(support|sales)@emailarchitect\.net$/"

        "/^(support|sales)@emailarchitect\.net$/" matches "support@emailarchitect.net" and "sales@emailarchitect.net".

        "/^[^@]+@emailarchitect\.net$/" matches "*@emailarchitect.net"
    -->
    <!--
    <add key="faked-emailarchitect.net" value="550 5.7.1 your message from [%blocked_domainOrAddress%] is in our black list." />
    <add key="spoof@faked-emailarchitect.net" value="550 5.7.1 your message from [%blocked_domainOrAddress%] is in our black list." />
    -->
</blockedSenderOrHeloDomain>

<!--
trustedIPAddresses:

The email from the following IP address(es) will be accepted directly regardless of SPF/DKIM result.
CIDR syntax is supported in IP address.
    -->
<trustedIPAddresses>
    <add key="127.0.0.1" value="pass"/>
    <add key="::1" value="pass"/>
    <!--
    <add key="192.168.0.0/24" value="pass"/>
    -->
</trustedIPAddresses>

<!--
trustedSenderOrDomain:

The email from (rfc822.header.from) the following address(es)/domain(s) will be accepted directly regardless of SPF/DKIM result.
    -->
<trustedSenderOrDomain>
    <!--
        You can use regular expression like this: "/^(support|sales)@emailarchitect\.net$/"

        "/^(support|sales)@emailarchitect\.net$/" matches "support@emailarchitect.net" and "sales@emailarchitect.net".

        "/^[^@]+@emailarchitect\.net$/" matches "*@emailarchitect.net"
    -->
    <!--
    <add key="support@emailarchitect.net" value="pass"/>
    <add key="emailarchitect.net" value="pass"/>
    -->
</trustedSenderOrDomain>

<appSettings>
    <add key ="logLevel" value="OnlyError"/>
    <!-- <add key ="LogLevel" value="FullDebug"/> -->
    <add key ="trackingSender" value="*"/>
    <add key ="trackingSourceIP" value="*"/>
    <add key ="useLastExternalIPAddress" value="false"/>
    <!-- System default DNS server is used by default, you don't have to set this value manually
    If you want to use specified DNS server address, you must input DNS server IP address.
    For example, you can use 8.8.8.8 (Google Public DNS Server) as the DNS server address.
-->
    <add key ="dnsServerAddress" value=""/>
</appSettings>
</configuration>

Simple Inbound DKIM/SPF/DMARC Test

To verify if inbound transport agent is working, change

<add key ="logLevel" value="OnlyError"/>

to:

<add key ="logLevel" value="FullDebug"/>

and then send a test email from outside domain. Do not send test email from Outlook/WebAccess, because those messages are internal message, it won’t trigger transport agent.

You will find the full debug log in installation path\log\YYYYDDMM.inbound.txt:

Here is a sample of full debug log:

#Name: DkimInboundAgent, ManagedThreadId=3
#Version: xxx
#Date: 2017-09-11 10:46:45.659

LogLevel: FullDebug
Static Counter: 1
IsUseLastExternalIPAddress: False
trackingSender: *
trackingSourceIP: *

.....

Bypass check with AntispamBypass and AuthenticationSource.

IP check with trusted-IP addresses.

[Message Source] ...


Start to test message for Authentication-Results (SPF/DKIM/DMARC).
10:46:45.690 smtpMailFromOrHeloDomain support@emailarchitect.net
10:46:45.690 senderIPAddress 104.214.112.138
10:46:45.690 query SPF text for emailarchitect.net
10:46:45.737 result: v=spf1 ip4:104.214.112.138 a mx ~all
....

10:46:45.737 104.214.112.138 is in 104.214.112.138/32
10:46:45.847 SPF Result: pass

10:46:45.690 parse email content with 1095 bytes
10:46:45.722 DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed;
s=s1024; d=emailarchitect.net;
h=message-id:from:to:subject:date:mime-version:content-type;
bh=8/5Y08pxf9kkHiNTMruAMt8ECrk=;
b=t2lEnuZvmkEpX5ulJMqtvN5O/fkfe4iw5vYPEtbWASgMU66Wp5roaJHONieQSX5F4UyKm95s
    kPc/lP2i8pvE85lSLqCsE+Zhcyi6zLIyWMQldbjXSuO5yjCaYfzHBPZGI8djIaVDWbTr/yMG
    W5X6rtNqu7g4COy5n2/0ELY7Q2o=

....

10:46:45.925 signature verified
10:46:45.925 DKIM Result: pass

10:46:45.925 SmtpMailFromOrHeloDomain support@emailarchitect.net
10:46:45.925 HeaderMailFrom support@emailarchitect.net
10:46:45.940 query dmarc text from _dmarc.emailarchitect.net
10:46:45.972 v=DMARC1; p=none
10:46:45.972 SPF Result: pass
10:46:45.972 DKIM Result: pass
10:46:45.972 evaluate alignment by v=DMARC1; p=none
10:46:45.972 SPF Alignment Result: pass
10:46:45.972 DKIM Alignment Result: pass
10:46:45.972 DMARC Result: pass

Detect if message should be rejected by SPF result.
Detect if message should be rejected by DKIM result.

Write Authentication-Results back to message stream:

Received-SPF: pass (localhost: domain of transitioning support@emailarchitect.net designates 104.214.112.138 as permitted sender) client-ip=104.214.112.138
Authentication-Results: exch2007.exch27.server;
    dkim=pass header.d=emailarchitect.net;
    spf=pass (localhost: domain of transitioning support@emailarchitect.net designates 104.214.112.138 as permitted sender) client-ip=104.214.112.138;
    dmarc=pass (adkim=r aspf=r p=none) header.from=emailarchitect.net;

Important

Because DKIM/SPF/DMARC agent doesn’t check the email from authenticated user in your organization, so you should send test email from outside domain to get the full process in the log.

Using Gmail, Hotmail account to do test is highly recommended, because those providers fully implemented SPF, DKIM and DMARC.

Filter Spam or Spoofing Email to Junk Folder based on DKIM/SPF Result

Now you can use the SPF or DKIM result to filter spam or spoofing email to junk folder. For example, if you want to filter emails with SPF fail or SPF softfail result to junk folder:

Create Transport Rule in Exchange 2007/2010

Edit Exchange Server Transport Rule.
  • Open Exchange Management Console -> Organization Configuration -> Hub Transport -> Transport Rule -> New Transport Rule;
  • Create a rule named “SPFRule”, select Condition to: when a message header contains specific words;
  • Set value in message header to Authentication-Results, and input “spf=fail” and “spf=softfail” two words in specific words.
  • Then set Actions to set the spam confidence leval value to, set value to 9.

After creating above rule, any emails from outside domain with SPF softfail and fail result will be filtered to junk folder in Exchange Server 2007/2010.

Create Transport Rule in Exchange 2013/2016/2019

Edit Exchange Server 2013/2016/2019 Transport Rule.
  • Open Exchange Admin Center (https://localhost/ecp) -> mail flow -> rules. Please change “localhost” to your server address if you access server remotely.
  • new rule -> Bypass spam filtering -> input “SPFRule” in rule name -> Apply this rule if A message header includes
  • Set header to Authentication-Results, and input “spf=fail” and “spf=softfail” two words in specific words.
  • In Do the following -> Modify the message properties -> Set spam confidence level (SCL) to.
  • Click Bypass spam filtering -> specify SCL -> Set value to 9 -> Click Save.

After creating above rule, any emails from outside domain with SPF softfail and fail result will be filtered to junk folder in Exchange Server 2013/2016/2019.

Reject Spam or Spoofing Email based on DKIM/SPF/DMARC Result in SMTP Service

Although you can use authenticate-results to filter email to junk folder, but it consumes server storage and resources. Moreover, if the email is filtered to junk folder, the sender doesn’t know the email is against your spam policy.

So the better way is rejecting email in SMTP service directly based on authenticate-results. If the email is rejected, the sender will receive non-delivery report from his SMTP server.

  • To reject the email against SPF policy, you can change spfResultToReject section.
  • To reject the email against DKIM policy, you can change dkimResultToReject section.
  • To reject the email against DMARC policy, you can change dmarcResultToReject section.

Trusted IP Addresses

You can add IP addresses to trustedIPAddresses section, Inbound DKIM/SPF agent won’t check the email from those IP addresses. It supports single IP address or CIDR syntax.

Here is an example:

<trustedIPAddresses>
    <add key="127.0.0.1" value="pass"/>
    <add key="192.168.0.0/24" value="pass"/>
</trustedIPAddresses>

Trusted Sender Or Domain

You can add sender addresses or domains to trustedSenderOrDomain section, Inbound DKIM/SPF agent won’t check the email from those sender or domain.

Here is an example:

<trustedSenderOrDomain>
  <!--
      You can use regular expression like this: "/^(support|sales)@emailarchitect\.net$/"

      "/^(support|sales)@emailarchitect\.net$/" matches "support@emailarchitect.net" and "sales@emailarchitect.net".

      "/^[^@]+@emailarchitect\.net$/" matches "*@emailarchitect.net"
  -->
  <add key="support@emailarchitect.net" value="pass"/>
  <add key="emailarchitect.net" value="pass"/>
</trustedSenderOrDomain>

Blocked IP Addresses

You can add IP addresses to blockedIPAddresses section, Inbound DKIM/SPF agent will reject the email from those addresses directly regardless of SPF/DKIM result. It supports single IP address or CIDR syntax.

<blockedIPAddresses>
    <add key="127.0.0.2" value="550 5.7.1 your message from [%source_ip%] is in our black list." />
</blockedIPAddresses>

Blocked Sender or Helo Domain

You can add sender addresses or domains to blockedSenderOrHeloDomain section, Inbound DKIM/SPF agent will reject the email from those sender or domain, or helo-domain (if sender address is null, helo-domain is checked).

<blockedSenderOrHeloDomain>
    <!--
        You can use regular expression like this: "/^(support|sales)@emailarchitect\.net$/"

        "/^(support|sales)@emailarchitect\.net$/" matches "support@emailarchitect.net" and "sales@emailarchitect.net".

        "/^[^@]+@emailarchitect\.net$/" matches "*@emailarchitect.net"
    -->
    <add key="faked-emailarchitect.net" value="550 5.7.1 your message from [%blocked_domainOrAddress%] is in our black list." />
    <add key="spoof@faked-emailarchitect.net" value="550 5.7.1 your message from [%blocked_domainOrAddress%] is in our black list." />
</blockedSenderOrHeloDomain>

Use Last External IP Address for SPF Check

By default, inbound SPF check uses current remote connection IP address. But if your current Exchange Server is behind of an edge server, Edge server IP address will override real remote IP address, so SPF check won’t return correct result. In this case, you should change useLastExternalIPAddress to true.

<add key ="useLastExternalIPAddress" value="true"/>

SPF Check Behind a Gateway/Firewall

If hasGateway is false, spf check uses current remote IP address to check spf policy; If hasGateway is true, spf check uses all possible IP addresses in email headers to check spf policy. If your server is behind of a gateway/firewall, please set this value to true.

<add key="hasGateway" value="true"/>

Important

ignoredGatewayIPAddressesForSpfCheck and ignoredGatewayNameForSpfCheck were obsoleted by hasGateway.

Excluded Organization IPAddresses

By default, all emails from AuthenticationSource: Organization or Partner will not be checked. But if you want to check emails from those servers, please add those server IP addresses to the following list like this:

<excludedOrganizationIPAddresses>
    <add key="192.168.0.16" value="check"/>
    <add key="192.168.0.0/24" value="check"/>
</excludedOrganizationIPAddresses>

Ignored Gateway IP Addresses for SPF Check

Important

This item is obsolete, Instead, use hasGateway in SPF Check Behind a Gateway/Firewall section.

If your Exchange Server is protected by anti-spam/anti-virus gateway, the gateway IP address also overrides real remote server IP address, that also caused SPF check returns incorrect result.

For example, if remote sender server IP address is 192.168.0.12, but your server MX record is set to an anti-spam gateway (IP 192.168.0.2), anti-spam gateway forwards the email to Exchange Server, by default, inbound SPF check uses current connection IP (anti-spam gateway [192.168.0.2]) to verify sender SPF policy, that is incorrect, SPF check should use sender server address (192.168.0.12) to verify SPF policy. To get the correct result, we should add 192.168.0.2 (gateway IP address) to ignoredGatewayIPAddressesForSpfCheck like this:

<!--
single IP or CIDR syntax is supported in IP address.
    -->
<ignoredGatewayIPAddressesForSpfCheck>
    <add key="192.168.0.2" value="ignore"/>
</ignoredGatewayIPAddressesForSpfCheck>

If you set ignoredGatewayIPAddressesForSpfCheck items, inbound SPF agent will parse IP addresses from message Received headers, by default Exchange SMTP service also adds a header with local server name and IP address, you should also add your local IP address to ignoredGatewayIPAddressesForSpfCheck.

I suggest that you enable Full Debug log level, and you will see how SPF guess the real remote IP address in log file, then you can add local/gateway IP addresses to ignoredGatewayIPAddressesForSpfCheck.

For example, if the headers in full debug log is like this:

Received: from my-exchange-server ([192.168.0.16]) by my-exchange-server ([192.168.0.16])
Received: from gateway1 ([192.168.0.2]) by my-exchange-server ([192.168.0.16]) ...
Received: from real-sender-server ([192.168.0.13]) by gateway1 ([192.168.0.2]) ...

To get correct result of SPF check, you can change ignoredGatewayIPAddressesForSpfCheck like this:

  <ignoredGatewayIPAddressesForSpfCheck>
    <add key="192.168.0.16" value="ignore"/>
    <add key="192.168.0.2" value="ignore"/>
</ignoredGatewayIPAddressesForSpfCheck>

With above options, inbound SPF agent will parse real sender IP address to 192.168.0.13.

Ignored Gateway Name for SPF Check

Important

This item is obsolete, Instead, use hasGateway in SPF Check Behind a Gateway/Firewall section.

If your gateway uses variable IP addresses, you can use gateway name to skip gateway IP addresses.

For example, if the headers in full debug log is like this:

Received: from my-exchange-server ([192.168.0.16]) by my-exchange-server ([192.168.0.16])
Received: from gateway1 ([192.168.0.2]) by my-exchange-server ([192.168.0.16]) ...
Received: from real-sender-server ([192.168.0.13]) by gateway1 ([192.168.0.2]) ...

To get correct result of SPF check, you can change ignoredGatewayNameForSpfCheck like this:

  <ignoredGatewayNameForSpfCheck>
    <add key="my-exchange-server" value="ignore"/>
    <add key="gateway1" value="ignore"/>
</ignoredGatewayNameForSpfCheck>

With gateway name options, no matter IP addresses used by gateway, inbound SPF agent can always parse real sender IP address to 192.168.0.13.

Troubleshooting and Journal

After you finished the test, you should change logLevel back to OnlyError, otherwise the log file will be very large. If you only want to track the message from specific IP address or sender, you can change logLevel to FullDebug, and add specific IP address or sender email address in trackingSourceIP or trackingSender.

FullDebug log only enables for sender “support@emailarchitect.net”.

<appSettings>
    <add key ="LogLevel" value="FullDebug"/>
    <add key ="trackingSender" value="support@emailarchitect.net"/>
    <add key ="trackingSourceIP" value="*"/>
    <add key ="useLastExternalIPAddress" value="false"/>
</appSettings>

FullDebug log only enables for source IP “127.0.0.1”.

<appSettings>
    <add key ="LogLevel" value="FullDebug"/>
    <add key ="trackingSender" value="*"/>
    <add key ="trackingSourceIP" value="127.0.0.1"/>
    <add key ="useLastExternalIPAddress" value="false"/>
</appSettings>

FullDebug log enables for both of source IP “127.0.0.1” and “support@emailarchitect.net

<appSettings>
    <add key ="LogLevel" value="FullDebug"/>
    <add key ="trackingSender" value="support@emailarchitect.net"/>
    <add key ="trackingSourceIP" value="127.0.0.1"/>
    <add key ="useLastExternalIPAddress" value="false"/>
</appSettings>

Note

You will find the full debug log in installation path\log\YYYYDDMM.inbound.txt:

DMARC Authentication

DMARC combines SPF and DKIM result, and it also specifies how to report the DKIM/SPF statistic report to domain owner.

Note

Because DKIM inbound agent doesn’t support to send report back to domain owner, so after DKIM is verified, only the DMARC result is written into Authentication-Results header.

Free Email Support

Not enough? Please contact our technical support team.

Support@EmailArchitect.NET

Remarks

We usually reply emails within 24hours. The reason for getting no response is likely that your smtp server bounced our reply. In this case, please try to use another email address to contact us. Your Gmail, Hotmail or Office 365 email account is recommended.