<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
  targetNamespace="http://dmarc.org/dmarc-xml/0.1"
  xmlns="http://dmarc.org/dmarc-xml/0.1">

<!-- The time range in UTC covered by messages in this report, specified in seconds since epoch. -->
<xs:complexType name="DateRangeType">
  <xs:all>
    <xs:element name="begin" type="xs:integer"/>
    <xs:element name="end" type="xs:integer"/>
  </xs:all>
</xs:complexType>

<!-- Report generator metadata -->
<xs:complexType name="ReportMetadataType">
  <xs:sequence>
    <xs:element name="org_name" type="xs:string"/>
    <xs:element name="email" type="xs:string"/>
    <xs:element name="extra_contact_info" type="xs:string" minOccurs="0"/>
    <xs:element name="report_id" type="xs:string"/>
    <xs:element name="date_range" type="DateRangeType"/>
    <xs:element name="error" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
  </xs:sequence>
</xs:complexType>

<!-- Alignment mode (relaxed or strict) for DKIM and SPF. -->
<xs:simpleType name="AlignmentType">
  <xs:restriction base="xs:string">
    <xs:enumeration value="r"/>
    <xs:enumeration value="s"/>
  </xs:restriction>
</xs:simpleType>

<!-- The policy actions specified by p and sp in the DMARC record. -->
<xs:simpleType name="DispositionType">
  <xs:restriction base="xs:string">
    <xs:enumeration value="none"/>
    <xs:enumeration value="quarantine"/>
    <xs:enumeration value="reject"/>
  </xs:restriction>
</xs:simpleType>

<!-- The DMARC policy that applied to the messages in this report. -->
<xs:complexType name="PolicyPublishedType">
  <xs:all>
    <!-- The domain at which the DMARC record was found. -->
    <xs:element name="domain" type="xs:string"/>
    <!-- The DKIM alignment mode. -->
    <xs:element name="adkim" type="AlignmentType"/>
    <!-- The SPF alignment mode. -->
    <xs:element name="aspf" type="AlignmentType"/>
    <!-- The policy to apply to messages from the domain. -->
    <xs:element name="p" type="DispositionType"/>
    <!-- The policy to apply to messages from subdomains. -->
    <xs:element name="sp" type="DispositionType"/>
    <!-- The percent of messages to which policy applies. -->
    <xs:element name="pct" type="xs:integer"/>
  </xs:all>
</xs:complexType>

<!-- The DMARC-aligned authentication result. -->
<xs:simpleType name="DMARCResultType">
  <xs:restriction base="xs:string">
    <xs:enumeration value="pass"/>
    <xs:enumeration value="fail"/>
  </xs:restriction>
</xs:simpleType>

<!-- Reasons that may affect DMARC disposition or execution thereof. -->
<!-- ==============================================================
Descriptions of the PolicyOverrideTypes:

forwarded:  Message was relayed via a known forwarder, or local
   heuristics identified the message as likely having been forwarded.
   There is no expectation that authentication would pass.

local_policy:  The Mail Receiver's local policy exempted the message
   from being subjected to the Domain Owner's requested policy
   action.

mailing_list:  Local heuristics determined that the message arrived
   via a mailing list, and thus authentication of the original
   message was not expected to succeed.

other:  Some policy exception not covered by the other entries in
   this list occurred.  Additional detail can be found in the
   PolicyOverrideReason's "comment" field.

sampled_out:  Message was exempted from application of policy by the
   "pct" setting in the DMARC policy record.

trusted_forwarder:  Message authentication failure was anticipated by
   other evidence linking the message to a locally-maintained list of
   known and trusted forwarders.
============================================================== -->

<xs:simpleType name="PolicyOverrideType">
  <xs:restriction base="xs:string">
    <xs:enumeration value="forwarded"/>
    <xs:enumeration value="sampled_out"/>
    <xs:enumeration value="trusted_forwarder"/>
    <xs:enumeration value="mailing_list"/>
    <xs:enumeration value="local_policy"/>
    <xs:enumeration value="other"/>
  </xs:restriction>
</xs:simpleType>

<!-- How do we allow report generators to include new classes of override reasons if they want to be more specific than "other"? -->
<xs:complexType name="PolicyOverrideReason">
  <xs:all>
    <xs:element name="type" type="PolicyOverrideType"/>
    <xs:element name="comment" type="xs:string"
               minOccurs="0"/>
  </xs:all>
</xs:complexType>

<!-- Taking into account everything else in the record, the results of applying DMARC. -->
<xs:complexType name="PolicyEvaluatedType">
  <xs:sequence>
    <xs:element name="disposition" type="DispositionType"/>
    <xs:element name="dkim" type="DMARCResultType"/>
    <xs:element name="spf" type="DMARCResultType"/>
    <xs:element name="reason" type="PolicyOverrideReason" minOccurs="0" maxOccurs="unbounded"/>
  </xs:sequence>
</xs:complexType>

<!-- Credit to Roger L. Costello for IPv4 regex http://mailman.ic.ac.uk/pipermail/xml-dev/1999-December/018018.html -->
<!-- Credit to java2s.com for IPv6 regex http://www.java2s.com/Code/XML/XML-Schema/IPv6addressesareeasiertodescribeusingasimpleregex.htm -->
<xs:simpleType name="IPAddress">
  <xs:restriction base="xs:string">
    <xs:pattern value="((1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]).){3}(1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])|([A-Fa-f0-9]{1,4}:){7}[A-Fa-f0-9]{1,4}"/>
  </xs:restriction>
</xs:simpleType>

<xs:complexType name="RowType">
  <xs:all>
    <!-- The connecting IP. -->
    <xs:element name="source_ip" type="IPAddress"/>
    <!-- The number of matching messages -->
    <xs:element name="count" type="xs:integer"/>
    <!-- The DMARC disposition applying to matching messages. -->
    <xs:element name="policy_evaluated" type="PolicyEvaluatedType" minOccurs="0"/>
  </xs:all>
</xs:complexType>

<xs:complexType name="IdentifierType">
  <xs:all>
    <!-- The envelope recipient domain. -->
    <xs:element name="envelope_to" type="xs:string" minOccurs="0"/>
    <!-- The payload From domain. -->
    <xs:element name="header_from" type="xs:string" minOccurs="1"/>
  </xs:all>
</xs:complexType>

<!-- DKIM verification result, according to RFC 5451 Section 2.4.1. -->
<xs:simpleType name="DKIMResultType">
  <xs:restriction base="xs:string">
    <xs:enumeration value="none"/>
    <xs:enumeration value="pass"/>
    <xs:enumeration value="fail"/>
    <xs:enumeration value="policy"/>
    <xs:enumeration value="neutral"/>
    <xs:enumeration value="temperror"/>
    <xs:enumeration value="permerror"/>
  </xs:restriction>
</xs:simpleType>

<xs:complexType name="DKIMAuthResultType">
  <xs:all>
    <!-- The d= parameter in the signature -->
    <xs:element name="domain" type="xs:string" minOccurs="1"/>
    <!-- The "s=" parameter in the signature. -->
    <xs:element name="selector" type="xs:string" minOccurs="0"/>
    <!-- The DKIM verification result -->
    <xs:element name="result" type="DKIMResultType" minOccurs="1"/>
    <!-- Any extra information (e.g., from Authentication-Results -->
    <xs:element name="human_result" type="xs:string" minOccurs="0"/>
  </xs:all>
</xs:complexType>

<!-- SPF result -->
<xs:simpleType name="SPFResultType">
  <xs:restriction base="xs:string">
    <xs:enumeration value="none"/>
    <xs:enumeration value="neutral"/>
    <xs:enumeration value="pass"/>
    <xs:enumeration value="fail"/>
    <xs:enumeration value="softfail"/>
    <!-- "TempError" commonly implemented as "unknown" -->
    <xs:enumeration value="temperror"/>
    <!-- "PermError" commonly implemented as "error" -->
    <xs:enumeration value="permerror"/>
  </xs:restriction>
</xs:simpleType>

<xs:complexType name="SPFAuthResultType">
  <xs:all>
    <!-- The envelope From domain. -->
    <xs:element name="domain" type="xs:string" minOccurs="1"/>
    <!-- The SPF verification result -->
    <xs:element name="result" type="SPFResultType" minOccurs="1"/>
  </xs:all>
</xs:complexType>

<!-- This element contains DKIM and SPF results, uninterpreted with respect to DMARC. -->
<xs:complexType name="AuthResultType">
  <xs:sequence>
    <!-- There may be no DKIM signatures, or multiple DKIM signatures. -->
    <xs:element name="dkim" type="DKIMAuthResultType" minOccurs="0" maxOccurs="unbounded"/>
    <!-- There will always be at least one SPF result. -->
    <xs:element name="spf" type="SPFAuthResultType" minOccurs="1" maxOccurs="unbounded"/>
  </xs:sequence>
</xs:complexType>

<!-- This element contains all the authentication results used to evaluate the DMARC disposition for the given set of messages. -->
<xs:complexType name="RecordType">
  <xs:sequence>
    <xs:element name="row" type="RowType"/>
    <xs:element name="identifiers" type="IdentifierType"/>
    <xs:element name="auth_results" type="AuthResultType"/>
  </xs:sequence>
</xs:complexType>

<!-- Parent -->
<xs:element name="feedback">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="report_metadata" type="ReportMetadataType"/>
      <xs:element name="policy_published" type="PolicyPublishedType"/>
      <xs:element name="record" type="RecordType" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>
</xs:schema>

