| # This is the openspf.org test suite (version 2007.05) based on RFC 4408. |
| # http://www.openspf.org/Test_Suite |
| # |
| # $Id$ |
| # vim:sw=2 sts=2 et |
| # |
| # See rfc4408-tests.CHANGES for a changelog. |
| # |
| # Contributors: |
| # Stuart D Gathman everything so far |
| # Julian Mehnle proofread YAML syntax, spelling, formal schema |
| # Informal contributors (suggestions but no code): |
| # Craig Whitmore |
| # Frank Ellermann |
| # Wayne Schlitt |
| # Scott Kitterman |
| # Norman Maurer |
| # Mark Shewmaker |
| # Philip Gladstone |
| # |
| --- |
| description: Initial processing |
| tests: |
| toolonglabel: |
| description: >- |
| DNS labels limited to 63 chars. |
| comment: >- |
| For initial processing, a long label results in None, not TempError |
| spec: 4.3/1 |
| helo: mail.example.net |
| host: 1.2.3.5 |
| mailfrom: lyme.eater@A123456789012345678901234567890123456789012345678901234567890123.example.com |
| result: none |
| longlabel: |
| description: >- |
| DNS labels limited to 63 chars. |
| spec: 4.3/1 |
| helo: mail.example.net |
| host: 1.2.3.5 |
| mailfrom: lyme.eater@A12345678901234567890123456789012345678901234567890123456789012.example.com |
| result: fail |
| emptylabel: |
| spec: 4.3/1 |
| helo: mail.example.net |
| host: 1.2.3.5 |
| mailfrom: lyme.eater@A...example.com |
| result: none |
| helo-not-fqdn: |
| spec: 4.3/1 |
| helo: A2345678 |
| host: 1.2.3.5 |
| mailfrom: "" |
| result: none |
| helo-domain-literal: |
| spec: 4.3/1 |
| helo: "[1.2.3.5]" |
| host: 1.2.3.5 |
| mailfrom: "" |
| result: none |
| nolocalpart: |
| spec: 4.3/2 |
| helo: mail.example.net |
| host: 1.2.3.4 |
| mailfrom: '@example.net' |
| result: fail |
| explanation: postmaster |
| domain-literal: |
| spec: 4.3/1 |
| helo: OEMCOMPUTER |
| host: 1.2.3.5 |
| mailfrom: "foo@[1.2.3.5]" |
| result: none |
| zonedata: |
| example.com: |
| - TIMEOUT |
| example.net: |
| - SPF: v=spf1 -all exp=exp.example.net |
| a.example.net: |
| - SPF: v=spf1 -all exp=exp.example.net |
| exp.example.net: |
| - TXT: '%{l}' |
| a12345678901234567890123456789012345678901234567890123456789012.example.com: |
| - SPF: v=spf1 -all |
| --- |
| description: Record lookup |
| tests: |
| both: |
| spec: 4.4/1 |
| helo: mail.example.net |
| host: 1.2.3.4 |
| mailfrom: foo@both.example.net |
| result: fail |
| txtonly: |
| description: Result is none if checking SPF records only. |
| spec: 4.4/1 |
| helo: mail.example.net |
| host: 1.2.3.4 |
| mailfrom: foo@txtonly.example.net |
| result: [fail, none] |
| spfonly: |
| description: Result is none if checking TXT records only. |
| spec: 4.4/1 |
| helo: mail.example.net |
| host: 1.2.3.4 |
| mailfrom: foo@spfonly.example.net |
| result: [fail, none] |
| spftimeout: |
| description: >- |
| TXT record present, but SPF lookup times out. |
| Result is temperror if checking SPF records only. |
| comment: >- |
| This actually happens for a popular braindead DNS server. |
| spec: 4.4/1 |
| helo: mail.example.net |
| host: 1.2.3.4 |
| mailfrom: foo@spftimeout.example.net |
| result: [fail, temperror] |
| txttimeout: |
| description: >- |
| SPF record present, but TXT lookup times out. |
| If only TXT records are checked, result is temperror. |
| spec: 4.4/1 |
| helo: mail.example.net |
| host: 1.2.3.4 |
| mailfrom: foo@txttimeout.example.net |
| result: [fail, temperror] |
| nospftxttimeout: |
| description: >- |
| No SPF record present, and TXT lookup times out. |
| If only TXT records are checked, result is temperror. |
| comment: >- |
| Because TXT records is where v=spf1 records will likely be, returning |
| temperror will try again later. A timeout due to a braindead server |
| is unlikely in the case of TXT, as opposed to the newer SPF RR. |
| spec: 4.4/1 |
| helo: mail.example.net |
| host: 1.2.3.4 |
| mailfrom: foo@nospftxttimeout.example.net |
| result: [temperror, none] |
| alltimeout: |
| description: Both TXT and SPF queries time out |
| spec: 4.4/2 |
| helo: mail.example.net |
| host: 1.2.3.4 |
| mailfrom: foo@alltimeout.example.net |
| result: temperror |
| zonedata: |
| both.example.net: |
| - TXT: v=spf1 -all |
| - SPF: v=spf1 -all |
| txtonly.example.net: |
| - TXT: v=spf1 -all |
| spfonly.example.net: |
| - SPF: v=spf1 -all |
| - TXT: NONE |
| spftimeout.example.net: |
| - TXT: v=spf1 -all |
| - TIMEOUT |
| txttimeout.example.net: |
| - SPF: v=spf1 -all |
| - TXT: NONE |
| - TIMEOUT |
| nospftxttimeout.example.net: |
| - SPF: "v=spf3 !a:yahoo.com -all" |
| - TXT: NONE |
| - TIMEOUT |
| alltimeout.example.net: |
| - TIMEOUT |
| --- |
| description: Selecting records |
| tests: |
| nospace1: |
| description: >- |
| Version must be terminated by space or end of record. TXT pieces |
| are joined without intervening spaces. |
| spec: 4.5/4 |
| helo: mail.example1.com |
| host: 1.2.3.4 |
| mailfrom: foo@example2.com |
| result: none |
| empty: |
| description: Empty SPF record. |
| spec: 4.5/4 |
| helo: mail1.example1.com |
| host: 1.2.3.4 |
| mailfrom: foo@example1.com |
| result: neutral |
| nospace2: |
| spec: 4.5/4 |
| helo: mail.example1.com |
| host: 1.2.3.4 |
| mailfrom: foo@example3.com |
| result: pass |
| spfoverride: |
| description: >- |
| SPF records override TXT records. Older implementation may |
| check TXT records only. |
| spec: 4.5/5 |
| helo: mail.example1.com |
| host: 1.2.3.4 |
| mailfrom: foo@example4.com |
| result: [pass, fail] |
| multitxt1: |
| description: >- |
| Older implementations will give permerror/unknown because of |
| the conflicting TXT records. However, RFC 4408 says the SPF |
| records overrides them. |
| spec: 4.5/5 |
| helo: mail.example1.com |
| host: 1.2.3.4 |
| mailfrom: foo@example5.com |
| result: [pass, permerror] |
| multitxt2: |
| description: >- |
| Multiple records is a permerror, v=spf1 is case insensitive |
| spec: 4.5/6 |
| helo: mail.example1.com |
| host: 1.2.3.4 |
| mailfrom: foo@example6.com |
| result: permerror |
| multispf1: |
| description: >- |
| Multiple records is a permerror, even when they are identical. |
| However, this situation cannot be reliably reproduced with live |
| DNS since cache and resolvers are allowed to combine identical |
| records. |
| spec: 4.5/6 |
| helo: mail.example1.com |
| host: 1.2.3.4 |
| mailfrom: foo@example7.com |
| result: [permerror, fail] |
| multispf2: |
| description: >- |
| Older implementations ignoring SPF-type records will give pass because |
| there is a (single) TXT record. But RFC 4408 requires permerror because |
| the SPF records override and there are more than one. |
| spec: 4.5/6 |
| helo: mail.example1.com |
| host: 1.2.3.4 |
| mailfrom: foo@example8.com |
| result: [permerror, pass] |
| nospf: |
| spec: 4.5/7 |
| helo: mail.example1.com |
| host: 1.2.3.4 |
| mailfrom: foo@mail.example1.com |
| result: none |
| case-insensitive: |
| description: >- |
| v=spf1 is case insensitive |
| spec: 4.5/6 |
| helo: mail.example1.com |
| host: 1.2.3.4 |
| mailfrom: foo@example9.com |
| result: softfail |
| zonedata: |
| example3.com: |
| - SPF: v=spf10 |
| - SPF: v=spf1 mx |
| - MX: [0, mail.example1.com] |
| example1.com: |
| - SPF: v=spf1 |
| example2.com: |
| - SPF: ['v=spf1', 'mx'] |
| mail.example1.com: |
| - A: 1.2.3.4 |
| example4.com: |
| - SPF: v=spf1 +all |
| - TXT: v=spf1 -all |
| example5.com: |
| - SPF: v=spf1 +all |
| - TXT: v=spf1 -all |
| - TXT: v=spf1 +all |
| example6.com: |
| - TXT: v=spf1 -all |
| - TXT: V=sPf1 +all |
| example7.com: |
| - SPF: v=spf1 -all |
| - SPF: v=spf1 -all |
| example8.com: |
| - SPF: V=spf1 -all |
| - SPF: v=spf1 -all |
| - TXT: v=spf1 +all |
| example9.com: |
| - SPF: v=SpF1 ~all |
| --- |
| description: Record evaluation |
| tests: |
| detect-errors-anywhere: |
| description: Any syntax errors anywhere in the record MUST be detected. |
| spec: 4.6 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@t1.example.com |
| result: permerror |
| modifier-charset-good: |
| description: name = ALPHA *( ALPHA / DIGIT / "-" / "_" / "." ) |
| spec: 4.6.1/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@t2.example.com |
| result: pass |
| modifier-charset-bad1: |
| description: >- |
| '=' character immediately after the name and before any ":" or "/" |
| spec: 4.6.1/4 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@t3.example.com |
| result: permerror |
| modifier-charset-bad2: |
| description: >- |
| '=' character immediately after the name and before any ":" or "/" |
| spec: 4.6.1/4 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@t4.example.com |
| result: permerror |
| redirect-after-mechanisms1: |
| description: >- |
| The "redirect" modifier has an effect after all the mechanisms. |
| comment: >- |
| The redirect in this example would violate processing limits, except |
| that it is never used because of the all mechanism. |
| spec: 4.6.3 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@t5.example.com |
| result: softfail |
| redirect-after-mechanisms2: |
| description: >- |
| The "redirect" modifier has an effect after all the mechanisms. |
| spec: 4.6.3 |
| helo: mail.example.com |
| host: 1.2.3.5 |
| mailfrom: foo@t6.example.com |
| result: fail |
| default-result: |
| description: Default result is neutral. |
| spec: 4.7/1 |
| helo: mail.example.com |
| host: 1.2.3.5 |
| mailfrom: foo@t7.example.com |
| result: neutral |
| redirect-is-modifier: |
| description: |- |
| Invalid mechanism. Redirect is a modifier. |
| spec: 4.6.1/4 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@t8.example.com |
| result: permerror |
| invalid-domain: |
| description: >- |
| Domain-spec must end in macro-expand or valid toplabel. |
| spec: 8.1/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@t9.example.com |
| result: permerror |
| invalid-domain-empty-label: |
| description: >- |
| Domain-spec must end in macro-expand or valid toplabel. |
| comment: >- |
| But anything goes before the toplabel. Empty labels cannot be |
| encoded for sending to a name server, so resolver must give error |
| or empty result. Empty result is analogous to 4.3/1, and so |
| is preferred. |
| spec: [8.1/2, 5/10] |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@t10.example.com |
| result: [fail, temperror] |
| invalid-domain-long: |
| description: >- |
| Domain-spec must end in macro-expand or valid toplabel. |
| comment: >- |
| But anything goes before the toplabel. Upper case H macro |
| url escapes the HELO string, the result is longer than 63 chars. |
| Long labels cannot be coded in a DNS query packet, so resolver must |
| give error or empty result. Empty result is analogous to 4.3/1, |
| and so is preferred. |
| spec: [8.1/2, 5/10] |
| helo: "%%%%%%%%%%%%%%%%%%%%%%" |
| host: 1.2.3.4 |
| mailfrom: foo@t11.example.com |
| result: [fail, temperror] |
| zonedata: |
| mail.example.com: |
| - A: 1.2.3.4 |
| t1.example.com: |
| - SPF: v=spf1 ip4:1.2.3.4 -all moo |
| t2.example.com: |
| - SPF: v=spf1 moo.cow-far_out=man:dog/cat ip4:1.2.3.4 -all |
| t3.example.com: |
| - SPF: v=spf1 moo.cow/far_out=man:dog/cat ip4:1.2.3.4 -all |
| t4.example.com: |
| - SPF: v=spf1 moo.cow:far_out=man:dog/cat ip4:1.2.3.4 -all |
| t5.example.com: |
| - SPF: v=spf1 redirect=t5.example.com ~all |
| t6.example.com: |
| - SPF: v=spf1 ip4:1.2.3.4 redirect=t2.example.com |
| t7.example.com: |
| - SPF: v=spf1 ip4:1.2.3.4 |
| t8.example.com: |
| - SPF: v=spf1 ip4:1.2.3.4 redirect:t2.example.com |
| t9.example.com: |
| - SPF: v=spf1 a:foo-bar -all |
| t10.example.com: |
| - SPF: v=spf1 a:mail.example...com -all |
| t11.example.com: |
| - SPF: v=spf1 a:%{H}.bar -all |
| --- |
| description: ALL mechanism syntax |
| tests: |
| all-dot: |
| description: | |
| all = "all" |
| comment: |- |
| At least one implementation got this wrong |
| spec: 5.1/1 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e1.example.com |
| result: permerror |
| all-arg: |
| description: | |
| all = "all" |
| comment: |- |
| At least one implementation got this wrong |
| spec: 5.1/1 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e2.example.com |
| result: permerror |
| all-cidr: |
| description: | |
| all = "all" |
| spec: 5.1/1 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e3.example.com |
| result: permerror |
| all-neutral: |
| description: | |
| all = "all" |
| spec: 5.1/1 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e4.example.com |
| result: neutral |
| all-double: |
| description: | |
| all = "all" |
| spec: 5.1/1 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e5.example.com |
| result: pass |
| zonedata: |
| mail.example.com: |
| - A: 1.2.3.4 |
| e1.example.com: |
| - SPF: v=spf1 -all. |
| e2.example.com: |
| - SPF: v=spf1 -all:foobar |
| e3.example.com: |
| - SPF: v=spf1 -all/8 |
| e4.example.com: |
| - SPF: v=spf1 ?all |
| e5.example.com: |
| - SPF: v=spf1 all -all |
| --- |
| description: PTR mechanism syntax |
| tests: |
| ptr-cidr: |
| description: |- |
| PTR = "ptr" [ ":" domain-spec ] |
| spec: 5.5/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e1.example.com |
| result: permerror |
| ptr-match-target: |
| description: >- |
| Check all validated domain names to see if they end in the <target-name> |
| domain. |
| spec: 5.5/5 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e2.example.com |
| result: pass |
| ptr-match-implicit: |
| description: >- |
| Check all validated domain names to see if they end in the <target-name> |
| domain. |
| spec: 5.5/5 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e3.example.com |
| result: pass |
| ptr-nomatch-invalid: |
| description: >- |
| Check all validated domain names to see if they end in the <target-name> |
| domain. |
| comment: >- |
| This PTR record does not validate |
| spec: 5.5/5 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e4.example.com |
| result: fail |
| ptr-match-ip6: |
| description: >- |
| Check all validated domain names to see if they end in the <target-name> |
| domain. |
| spec: 5.5/5 |
| helo: mail.example.com |
| host: CAFE:BABE::1 |
| mailfrom: foo@e3.example.com |
| result: pass |
| ptr-empty-domain: |
| description: >- |
| domain-spec cannot be empty. |
| spec: 5.5/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e5.example.com |
| result: permerror |
| zonedata: |
| mail.example.com: |
| - A: 1.2.3.4 |
| e1.example.com: |
| - SPF: v=spf1 ptr/0 -all |
| e2.example.com: |
| - SPF: v=spf1 ptr:example.com -all |
| 4.3.2.1.in-addr.arpa: |
| - PTR: e3.example.com |
| - PTR: e4.example.com |
| - PTR: mail.example.com |
| 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.E.B.A.B.E.F.A.C.ip6.arpa: |
| - PTR: e3.example.com |
| e3.example.com: |
| - SPF: v=spf1 ptr -all |
| - A: 1.2.3.4 |
| - AAAA: CAFE:BABE::1 |
| e4.example.com: |
| - SPF: v=spf1 ptr -all |
| e5.example.com: |
| - SPF: "v=spf1 ptr:" |
| --- |
| description: A mechanism syntax |
| tests: |
| a-cidr6: |
| description: | |
| A = "a" [ ":" domain-spec ] [ dual-cidr-length ] |
| dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ] |
| spec: 5.3/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e6.example.com |
| result: fail |
| a-bad-cidr4: |
| description: | |
| A = "a" [ ":" domain-spec ] [ dual-cidr-length ] |
| dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ] |
| spec: 5.3/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e6a.example.com |
| result: permerror |
| a-bad-cidr6: |
| description: | |
| A = "a" [ ":" domain-spec ] [ dual-cidr-length ] |
| dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ] |
| spec: 5.3/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e7.example.com |
| result: permerror |
| a-multi-ip1: |
| description: >- |
| A matches any returned IP. |
| spec: 5.3/3 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e10.example.com |
| result: pass |
| a-multi-ip2: |
| description: >- |
| A matches any returned IP. |
| spec: 5.3/3 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e10.example.com |
| result: pass |
| a-bad-domain: |
| description: >- |
| domain-spec must pass basic syntax checks |
| comment: >- |
| A ':' may appear in domain-spec, but not in top-label. |
| spec: 8.1/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e9.example.com |
| result: permerror |
| a-nxdomain: |
| description: >- |
| If no ips are returned, A mechanism does not match, even with /0. |
| spec: 5.3/3 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e1.example.com |
| result: fail |
| a-cidr4-0: |
| description: >- |
| Matches if any A records are present in DNS. |
| spec: 5.3/3 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e2.example.com |
| result: pass |
| a-cidr4-0-ip6: |
| description: >- |
| Matches if any A records are present in DNS. |
| spec: 5.3/3 |
| helo: mail.example.com |
| host: 1234::1 |
| mailfrom: foo@e2.example.com |
| result: fail |
| a-cidr6-0-ip4: |
| description: >- |
| Would match if any AAAA records are present in DNS, |
| but not for an IP4 connection. |
| spec: 5.3/3 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e2a.example.com |
| result: fail |
| a-cidr6-0-ip4mapped: |
| description: >- |
| Would match if any AAAA records are present in DNS, |
| but not for an IP4 connection. |
| spec: 5.3/3 |
| helo: mail.example.com |
| host: ::FFFF:1.2.3.4 |
| mailfrom: foo@e2a.example.com |
| result: fail |
| a-cidr6-0-ip6: |
| description: >- |
| Matches if any AAAA records are present in DNS. |
| spec: 5.3/3 |
| helo: mail.example.com |
| host: 1234::1 |
| mailfrom: foo@e2a.example.com |
| result: pass |
| a-cidr6-0-nxdomain: |
| description: >- |
| No match if no AAAA records are present in DNS. |
| spec: 5.3/3 |
| helo: mail.example.com |
| host: 1234::1 |
| mailfrom: foo@e2b.example.com |
| result: fail |
| a-null: |
| description: >- |
| Null not allowed in top-label. |
| spec: 8.1/2 |
| helo: mail.example.com |
| host: 1.2.3.5 |
| mailfrom: foo@e3.example.com |
| result: permerror |
| a-numeric: |
| description: >- |
| Top-label may not be all numeric |
| comment: >- |
| A common publishing mistake is using ip4 addresses with A mechanism. |
| This should receive special diagnostic attention in the permerror. |
| spec: 8.1/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e4.example.com |
| result: permerror |
| a-numeric-top-label: |
| description: >- |
| Top-label may not be all numeric |
| spec: 8.1/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e5.example.com |
| result: permerror |
| a-only-top-label: |
| description: >- |
| Domain-spec may not consist of only a top-label without a leading dot. |
| spec: 8.1/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e5a.example.com |
| result: permerror |
| a-colon-domain: |
| description: >- |
| Domain-spec may contain any visible char except % |
| spec: 8.1/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e11.example.com |
| result: pass |
| a-colon-domain-ip4mapped: |
| description: >- |
| Domain-spec may contain any visible char except % |
| spec: 8.1/2 |
| helo: mail.example.com |
| host: ::FFFF:1.2.3.4 |
| mailfrom: foo@e11.example.com |
| result: pass |
| a-bad-toplab: |
| description: >- |
| Toplabel may not begin with - |
| spec: 8.1/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e12.example.com |
| result: permerror |
| a-empty-domain: |
| description: >- |
| domain-spec cannot be empty. |
| spec: 5.3/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e13.example.com |
| result: permerror |
| a-valid-syntax-but-unqueryable: |
| description: >- |
| If a DNS-interactive mechanism has valid syntax according to the SPF |
| specification, but a DNS query cannot be composed from its target-name |
| (e.g. due to empty labels, i.e. two or more successive dots), then the |
| mechanism should be treated as a no-match. |
| comment: >- |
| The rationale is that, technically, the mechanism is not a syntax error, |
| and the odd target-name obviously cannot exist in DNS. |
| spec: 8.1/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e14.example.com |
| result: neutral |
| zonedata: |
| mail.example.com: |
| - A: 1.2.3.4 |
| e1.example.com: |
| - SPF: v=spf1 a/0 -all |
| e2.example.com: |
| - A: 1.1.1.1 |
| - AAAA: 1234::2 |
| - SPF: v=spf1 a/0 -all |
| e2a.example.com: |
| - AAAA: 1234::1 |
| - SPF: v=spf1 a//0 -all |
| e2b.example.com: |
| - A: 1.1.1.1 |
| - SPF: v=spf1 a//0 -all |
| e3.example.com: |
| - SPF: "v=spf1 a:foo.example.com\0" |
| e4.example.com: |
| - SPF: v=spf1 a:111.222.33.44 |
| e5.example.com: |
| - SPF: v=spf1 a:abc.123 |
| e5a.example.com: |
| - SPF: v=spf1 a:museum |
| e6.example.com: |
| - SPF: v=spf1 a//33 -all |
| e6a.example.com: |
| - SPF: v=spf1 a/33 -all |
| e7.example.com: |
| - SPF: v=spf1 a//129 -all |
| e9.example.com: |
| - SPF: v=spf1 a:example.com:8080 |
| e10.example.com: |
| - SPF: v=spf1 a:foo.example.com/24 |
| foo.example.com: |
| - A: 1.1.1.1 |
| - A: 1.2.3.5 |
| e11.example.com: |
| - SPF: v=spf1 a:foo:bar/baz.example.com |
| foo:bar/baz.example.com: |
| - A: 1.2.3.4 |
| e12.example.com: |
| - SPF: v=spf1 a:example.-com |
| e13.example.com: |
| - SPF: "v=spf1 a:" |
| e14.example.com: |
| - SPF: v=spf1 a:example..com |
| --- |
| description: Include mechanism semantics and syntax |
| tests: |
| include-fail: |
| description: >- |
| recursive check_host() result of fail causes include to not match. |
| spec: 5.2/9 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e1.example.com |
| result: softfail |
| include-softfail: |
| description: >- |
| recursive check_host() result of softfail causes include to not match. |
| spec: 5.2/9 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e2.example.com |
| result: pass |
| include-neutral: |
| description: >- |
| recursive check_host() result of neutral causes include to not match. |
| spec: 5.2/9 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e3.example.com |
| result: fail |
| include-temperror: |
| description: >- |
| recursive check_host() result of temperror causes include to temperror |
| spec: 5.2/9 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e4.example.com |
| result: temperror |
| include-permerror: |
| description: >- |
| recursive check_host() result of permerror causes include to permerror |
| spec: 5.2/9 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e5.example.com |
| result: permerror |
| include-syntax-error: |
| description: >- |
| include = "include" ":" domain-spec |
| spec: 5.2/1 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e6.example.com |
| result: permerror |
| include-cidr: |
| description: >- |
| include = "include" ":" domain-spec |
| spec: 5.2/1 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e9.example.com |
| result: permerror |
| include-none: |
| description: >- |
| recursive check_host() result of none causes include to permerror |
| spec: 5.2/9 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e7.example.com |
| result: permerror |
| include-empty-domain: |
| description: >- |
| domain-spec cannot be empty. |
| spec: 5.2/1 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e8.example.com |
| result: permerror |
| zonedata: |
| mail.example.com: |
| - A: 1.2.3.4 |
| ip5.example.com: |
| - SPF: v=spf1 ip4:1.2.3.5 -all |
| ip6.example.com: |
| - SPF: v=spf1 ip4:1.2.3.6 ~all |
| ip7.example.com: |
| - SPF: v=spf1 ip4:1.2.3.7 ?all |
| ip8.example.com: |
| - TIMEOUT |
| erehwon.example.com: |
| - TXT: v=spfl am not an SPF record |
| e1.example.com: |
| - SPF: v=spf1 include:ip5.example.com ~all |
| e2.example.com: |
| - SPF: v=spf1 include:ip6.example.com all |
| e3.example.com: |
| - SPF: v=spf1 include:ip7.example.com -all |
| e4.example.com: |
| - SPF: v=spf1 include:ip8.example.com -all |
| e5.example.com: |
| - SPF: v=spf1 include:e6.example.com -all |
| e6.example.com: |
| - SPF: v=spf1 include +all |
| e7.example.com: |
| - SPF: v=spf1 include:erehwon.example.com -all |
| e8.example.com: |
| - SPF: "v=spf1 include: -all" |
| e9.example.com: |
| - SPF: "v=spf1 include:ip5.example.com/24 -all" |
| --- |
| description: MX mechanism syntax |
| tests: |
| mx-cidr6: |
| description: | |
| MX = "mx" [ ":" domain-spec ] [ dual-cidr-length ] |
| dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ] |
| spec: 5.4/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e6.example.com |
| result: fail |
| mx-bad-cidr4: |
| description: | |
| MX = "mx" [ ":" domain-spec ] [ dual-cidr-length ] |
| dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ] |
| spec: 5.4/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e6a.example.com |
| result: permerror |
| mx-bad-cidr6: |
| description: | |
| MX = "mx" [ ":" domain-spec ] [ dual-cidr-length ] |
| dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ] |
| spec: 5.4/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e7.example.com |
| result: permerror |
| mx-multi-ip1: |
| description: >- |
| MX matches any returned IP. |
| spec: 5.4/3 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e10.example.com |
| result: pass |
| mx-multi-ip2: |
| description: >- |
| MX matches any returned IP. |
| spec: 5.4/3 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e10.example.com |
| result: pass |
| mx-bad-domain: |
| description: >- |
| domain-spec must pass basic syntax checks |
| comment: >- |
| A ':' may appear in domain-spec, but not in top-label. |
| spec: 8.1/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e9.example.com |
| result: permerror |
| mx-nxdomain: |
| description: >- |
| If no ips are returned, MX mechanism does not match, even with /0. |
| spec: 5.4/3 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e1.example.com |
| result: fail |
| mx-cidr4-0: |
| description: >- |
| Matches if any A records for any MX records are present in DNS. |
| spec: 5.4/3 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e2.example.com |
| result: pass |
| mx-cidr4-0-ip6: |
| description: >- |
| Matches if any A records for any MX records are present in DNS. |
| spec: 5.4/3 |
| helo: mail.example.com |
| host: 1234::1 |
| mailfrom: foo@e2.example.com |
| result: fail |
| mx-cidr6-0-ip4: |
| description: >- |
| Would match if any AAAA records for MX records are present in DNS, |
| but not for an IP4 connection. |
| spec: 5.4/3 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e2a.example.com |
| result: fail |
| mx-cidr6-0-ip4mapped: |
| description: >- |
| Would match if any AAAA records for MX records are present in DNS, |
| but not for an IP4 connection. |
| spec: 5.4/3 |
| helo: mail.example.com |
| host: ::FFFF:1.2.3.4 |
| mailfrom: foo@e2a.example.com |
| result: fail |
| mx-cidr6-0-ip6: |
| description: >- |
| Matches if any AAAA records for any MX records are present in DNS. |
| spec: 5.3/3 |
| helo: mail.example.com |
| host: 1234::1 |
| mailfrom: foo@e2a.example.com |
| result: pass |
| mx-cidr6-0-nxdomain: |
| description: >- |
| No match if no AAAA records for any MX records are present in DNS. |
| spec: 5.4/3 |
| helo: mail.example.com |
| host: 1234::1 |
| mailfrom: foo@e2b.example.com |
| result: fail |
| mx-null: |
| description: >- |
| Null not allowed in top-label. |
| spec: 8.1/2 |
| helo: mail.example.com |
| host: 1.2.3.5 |
| mailfrom: foo@e3.example.com |
| result: permerror |
| mx-numeric-top-label: |
| description: >- |
| Top-label may not be all numeric |
| spec: 8.1/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e5.example.com |
| result: permerror |
| mx-colon-domain: |
| description: >- |
| Domain-spec may contain any visible char except % |
| spec: 8.1/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e11.example.com |
| result: pass |
| mx-colon-domain-ip4mapped: |
| description: >- |
| Domain-spec may contain any visible char except % |
| spec: 8.1/2 |
| helo: mail.example.com |
| host: ::FFFF:1.2.3.4 |
| mailfrom: foo@e11.example.com |
| result: pass |
| mx-bad-toplab: |
| description: >- |
| Toplabel may not begin with - |
| spec: 8.1/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e12.example.com |
| result: permerror |
| mx-empty: |
| description: >- |
| test null MX |
| comment: >- |
| Some implementations have had trouble with null MX |
| spec: 5.4/3 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: "" |
| result: neutral |
| mx-implicit: |
| description: >- |
| If the target name has no MX records, check_host() MUST NOT pretend the |
| target is its single MX, and MUST NOT default to an A lookup on the |
| target-name directly. |
| spec: 5.4/4 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e4.example.com |
| result: neutral |
| mx-empty-domain: |
| description: >- |
| domain-spec cannot be empty. |
| spec: 5.2/1 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e13.example.com |
| result: permerror |
| zonedata: |
| mail.example.com: |
| - A: 1.2.3.4 |
| - MX: [0, ""] |
| - SPF: v=spf1 mx |
| e1.example.com: |
| - SPF: v=spf1 mx/0 -all |
| - MX: [0, e1.example.com] |
| e2.example.com: |
| - A: 1.1.1.1 |
| - AAAA: 1234::2 |
| - MX: [0, e2.example.com] |
| - SPF: v=spf1 mx/0 -all |
| e2a.example.com: |
| - AAAA: 1234::1 |
| - MX: [0, e2a.example.com] |
| - SPF: v=spf1 mx//0 -all |
| e2b.example.com: |
| - A: 1.1.1.1 |
| - MX: [0, e2b.example.com] |
| - SPF: v=spf1 mx//0 -all |
| e3.example.com: |
| - SPF: "v=spf1 mx:foo.example.com\0" |
| e4.example.com: |
| - SPF: v=spf1 mx |
| - A: 1.2.3.4 |
| e5.example.com: |
| - SPF: v=spf1 mx:abc.123 |
| e6.example.com: |
| - SPF: v=spf1 mx//33 -all |
| e6a.example.com: |
| - SPF: v=spf1 mx/33 -all |
| e7.example.com: |
| - SPF: v=spf1 mx//129 -all |
| e9.example.com: |
| - SPF: v=spf1 mx:example.com:8080 |
| e10.example.com: |
| - SPF: v=spf1 mx:foo.example.com/24 |
| foo.example.com: |
| - MX: [0, foo1.example.com] |
| foo1.example.com: |
| - A: 1.1.1.1 |
| - A: 1.2.3.5 |
| e11.example.com: |
| - SPF: v=spf1 mx:foo:bar/baz.example.com |
| foo:bar/baz.example.com: |
| - MX: [0, "foo:bar/baz.example.com"] |
| - A: 1.2.3.4 |
| e12.example.com: |
| - SPF: v=spf1 mx:example.-com |
| e13.example.com: |
| - SPF: "v=spf1 mx: -all" |
| --- |
| description: EXISTS mechanism syntax |
| tests: |
| exists-empty-domain: |
| description: >- |
| domain-spec cannot be empty. |
| spec: 5.7/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e1.example.com |
| result: permerror |
| exists-implicit: |
| description: >- |
| exists = "exists" ":" domain-spec |
| spec: 5.7/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e2.example.com |
| result: permerror |
| exists-cidr: |
| description: >- |
| exists = "exists" ":" domain-spec |
| spec: 5.7/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e3.example.com |
| result: permerror |
| zonedata: |
| mail.example.com: |
| - A: 1.2.3.4 |
| e1.example.com: |
| - SPF: "v=spf1 exists:" |
| e2.example.com: |
| - SPF: "v=spf1 exists" |
| e3.example.com: |
| - SPF: "v=spf1 exists:mail.example.com/24" |
| --- |
| description: IP4 mechanism syntax |
| tests: |
| cidr4-0: |
| description: >- |
| ip4-cidr-length = "/" 1*DIGIT |
| spec: 5.6/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e1.example.com |
| result: pass |
| cidr4-32: |
| description: >- |
| ip4-cidr-length = "/" 1*DIGIT |
| spec: 5.6/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e2.example.com |
| result: pass |
| cidr4-33: |
| description: >- |
| Invalid CIDR should get permerror. |
| comment: >- |
| The RFC is silent on ip4 CIDR > 32 or ip6 CIDR > 128. However, |
| since there is no reasonable interpretation (except a noop), we have |
| read between the lines to see a prohibition on invalid CIDR. |
| spec: 5.6/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e3.example.com |
| result: permerror |
| cidr4-032: |
| description: >- |
| Invalid CIDR should get permerror. |
| comment: >- |
| Leading zeros are not explicitly prohibited by the RFC. However, |
| since the RFC explicity prohibits leading zeros in ip4-network, |
| our interpretation is that CIDR should be also. |
| spec: 5.6/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e4.example.com |
| result: permerror |
| bare-ip4: |
| description: >- |
| IP4 = "ip4" ":" ip4-network [ ip4-cidr-length ] |
| spec: 5.6/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e5.example.com |
| result: permerror |
| bad-ip4-port: |
| description: >- |
| IP4 = "ip4" ":" ip4-network [ ip4-cidr-length ] |
| comment: >- |
| This has actually been published in SPF records. |
| spec: 5.6/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e8.example.com |
| result: permerror |
| bad-ip4-short: |
| description: >- |
| It is not permitted to omit parts of the IP address instead of |
| using CIDR notations. |
| spec: 5.6/4 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e9.example.com |
| result: permerror |
| ip4-dual-cidr: |
| description: >- |
| dual-cidr-length not permitted on ip4 |
| spec: 5.6/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e6.example.com |
| result: permerror |
| ip4-mapped-ip6: |
| description: >- |
| IP4 mapped IP6 connections MUST be treated as IP4 |
| spec: 5/9/2 |
| helo: mail.example.com |
| host: ::FFFF:1.2.3.4 |
| mailfrom: foo@e7.example.com |
| result: fail |
| zonedata: |
| mail.example.com: |
| - A: 1.2.3.4 |
| e1.example.com: |
| - SPF: v=spf1 ip4:1.1.1.1/0 -all |
| e2.example.com: |
| - SPF: v=spf1 ip4:1.2.3.4/32 -all |
| e3.example.com: |
| - SPF: v=spf1 ip4:1.2.3.4/33 -all |
| e4.example.com: |
| - SPF: v=spf1 ip4:1.2.3.4/032 -all |
| e5.example.com: |
| - SPF: v=spf1 ip4 |
| e6.example.com: |
| - SPF: v=spf1 ip4:1.2.3.4//32 |
| e7.example.com: |
| - SPF: v=spf1 -ip4:1.2.3.4 ip6:::FFFF:1.2.3.4 |
| e8.example.com: |
| - SPF: v=spf1 ip4:1.2.3.4:8080 |
| e9.example.com: |
| - SPF: v=spf1 ip4:1.2.3 |
| --- |
| description: IP6 mechanism syntax |
| comment: >- |
| IP4 only implementations may skip tests where host is not IP4 |
| tests: |
| bare-ip6: |
| description: >- |
| IP6 = "ip6" ":" ip6-network [ ip6-cidr-length ] |
| spec: 5.6/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e1.example.com |
| result: permerror |
| cidr6-0-ip4: |
| description: >- |
| IP4 connections do not match ip6. |
| comment: >- |
| There is controversy over ip4 mapped connections. RFC4408 clearly |
| requires such connections to be considered as ip4. However, |
| some interpret the RFC to mean that such connections should *also* |
| match appropriate ip6 mechanisms (but not, inexplicably, A or MX |
| mechanisms). Until there is consensus, both |
| results are acceptable. |
| spec: 5/9/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e2.example.com |
| result: [neutral, pass] |
| cidr6-ip4: |
| description: >- |
| Even if the SMTP connection is via IPv6, an IPv4-mapped IPv6 IP address |
| (see RFC 3513, Section 2.5.5) MUST still be considered an IPv4 address. |
| comment: >- |
| There is controversy over ip4 mapped connections. RFC4408 clearly |
| requires such connections to be considered as ip4. However, |
| some interpret the RFC to mean that such connections should *also* |
| match appropriate ip6 mechanisms (but not, inexplicably, A or MX |
| mechanisms). Until there is consensus, both |
| results are acceptable. |
| spec: 5/9/2 |
| helo: mail.example.com |
| host: ::FFFF:1.2.3.4 |
| mailfrom: foo@e2.example.com |
| result: [neutral, pass] |
| cidr6-0: |
| description: >- |
| Match any IP6 |
| spec: 5/8 |
| helo: mail.example.com |
| host: DEAF:BABE::CAB:FEE |
| mailfrom: foo@e2.example.com |
| result: pass |
| cidr6-129: |
| description: >- |
| Invalid CIDR |
| comment: >- |
| IP4 only implementations MUST fully syntax check all mechanisms, |
| even if they otherwise ignore them. |
| spec: 5.6/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e3.example.com |
| result: permerror |
| cidr6-bad: |
| description: >- |
| dual-cidr syntax not used for ip6 |
| comment: >- |
| IP4 only implementations MUST fully syntax check all mechanisms, |
| even if they otherwise ignore them. |
| spec: 5.6/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e4.example.com |
| result: permerror |
| cidr6-33: |
| description: >- |
| make sure ip4 cidr restriction are not used for ip6 |
| spec: 5.6/2 |
| helo: mail.example.com |
| host: "CAFE:BABE:8000::" |
| mailfrom: foo@e5.example.com |
| result: pass |
| cidr6-33-ip4: |
| description: >- |
| make sure ip4 cidr restriction are not used for ip6 |
| spec: 5.6/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e5.example.com |
| result: neutral |
| ip6-bad1: |
| description: >- |
| spec: 5.6/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e6.example.com |
| result: permerror |
| zonedata: |
| mail.example.com: |
| - A: 1.2.3.4 |
| e1.example.com: |
| - SPF: v=spf1 -all ip6 |
| e2.example.com: |
| - SPF: v=spf1 ip6:::1.1.1.1/0 |
| e3.example.com: |
| - SPF: v=spf1 ip6:::1.1.1.1/129 |
| e4.example.com: |
| - SPF: v=spf1 ip6:::1.1.1.1//33 |
| e5.example.com: |
| - SPF: v=spf1 ip6:CAFE:BABE:8000::/33 |
| e6.example.com: |
| - SPF: v=spf1 ip6::CAFE::BABE |
| --- |
| description: Semantics of exp and other modifiers |
| comment: >- |
| Implementing exp= is optional. If not implemented, the test driver should |
| not check the explanation field. |
| tests: |
| redirect-none: |
| description: >- |
| If no SPF record is found, or if the target-name is malformed, the result |
| is a "PermError" rather than "None". |
| spec: 6.1/4 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e10.example.com |
| result: permerror |
| redirect-cancels-exp: |
| description: >- |
| when executing "redirect", exp= from the original domain MUST NOT be used. |
| spec: 6.2/13 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e1.example.com |
| result: fail |
| explanation: DEFAULT |
| redirect-syntax-error: |
| description: | |
| redirect = "redirect" "=" domain-spec |
| comment: >- |
| A literal application of the grammar causes modifier syntax |
| errors (except for macro syntax) to become unknown-modifier. |
| |
| modifier = explanation | redirect | unknown-modifier |
| |
| However, it is generally agreed, with precedent in other RFCs, |
| that unknown-modifier should not be "greedy", and should not |
| match known modifier names. There should have been explicit |
| prose to this effect, and some has been proposed as an erratum. |
| spec: 6.1/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e17.example.com |
| result: permerror |
| include-ignores-exp: |
| description: >- |
| when executing "include", exp= from the target domain MUST NOT be used. |
| spec: 6.2/13 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e7.example.com |
| result: fail |
| explanation: Correct! |
| redirect-cancels-prior-exp: |
| description: >- |
| when executing "redirect", exp= from the original domain MUST NOT be used. |
| spec: 6.2/13 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e3.example.com |
| result: fail |
| explanation: See me. |
| invalid-modifier: |
| description: | |
| unknown-modifier = name "=" macro-string |
| name = ALPHA *( ALPHA / DIGIT / "-" / "_" / "." ) |
| comment: >- |
| Unknown modifier name must begin with alpha. |
| spec: A/3 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e5.example.com |
| result: permerror |
| empty-modifier-name: |
| description: | |
| name = ALPHA *( ALPHA / DIGIT / "-" / "_" / "." ) |
| comment: >- |
| Unknown modifier name must not be empty. |
| spec: A/3 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e6.example.com |
| result: permerror |
| dorky-sentinel: |
| description: >- |
| An implementation that uses a legal expansion as a sentinel. We |
| cannot check them all, but we can check this one. |
| comment: >- |
| Spaces are allowed in local-part. |
| spec: 8.1/6 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: "Macro Error@e8.example.com" |
| result: fail |
| explanation: Macro Error in implementation |
| exp-multiple-txt: |
| description: | |
| Ignore exp if multiple TXT records. |
| comment: >- |
| If domain-spec is empty, or there are any DNS processing errors (any |
| RCODE other than 0), or if no records are returned, or if more than one |
| record is returned, or if there are syntax errors in the explanation |
| string, then proceed as if no exp modifier was given. |
| spec: 6.2/4 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e11.example.com |
| result: fail |
| explanation: DEFAULT |
| exp-no-txt: |
| description: | |
| Ignore exp if no TXT records. |
| comment: >- |
| If domain-spec is empty, or there are any DNS processing errors (any |
| RCODE other than 0), or if no records are returned, or if more than one |
| record is returned, or if there are syntax errors in the explanation |
| string, then proceed as if no exp modifier was given. |
| spec: 6.2/4 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e22.example.com |
| result: fail |
| explanation: DEFAULT |
| exp-dns-error: |
| description: | |
| Ignore exp if DNS error. |
| comment: >- |
| If domain-spec is empty, or there are any DNS processing errors (any |
| RCODE other than 0), or if no records are returned, or if more than one |
| record is returned, or if there are syntax errors in the explanation |
| string, then proceed as if no exp modifier was given. |
| spec: 6.2/4 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e21.example.com |
| result: fail |
| explanation: DEFAULT |
| exp-empty-domain: |
| description: | |
| PermError if exp= domain-spec is empty. |
| comment: >- |
| Section 6.2/4 says, "If domain-spec is empty, or there are any DNS |
| processing errors (any RCODE other than 0), or if no records are |
| returned, or if more than one record is returned, or if there are syntax |
| errors in the explanation string, then proceed as if no exp modifier was |
| given." However, "if domain-spec is empty" conflicts with the grammar |
| given for the exp modifier. This was reported as an erratum, and the |
| solution chosen was to report explicit "exp=" as PermError, but ignore |
| problems due to macro expansion, DNS, or invalid explanation string. |
| spec: 6.2/4 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e12.example.com |
| result: permerror |
| explanation-syntax-error: |
| description: | |
| Ignore exp if the explanation string has a syntax error. |
| comment: >- |
| If domain-spec is empty, or there are any DNS processing errors (any |
| RCODE other than 0), or if no records are returned, or if more than one |
| record is returned, or if there are syntax errors in the explanation |
| string, then proceed as if no exp modifier was given. |
| spec: 6.2/4 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e13.example.com |
| result: fail |
| explanation: DEFAULT |
| exp-syntax-error: |
| description: | |
| explanation = "exp" "=" domain-spec |
| comment: >- |
| A literal application of the grammar causes modifier syntax |
| errors (except for macro syntax) to become unknown-modifier. |
| |
| modifier = explanation | redirect | unknown-modifier |
| |
| However, it is generally agreed, with precedent in other RFCs, |
| that unknown-modifier should not be "greedy", and should not |
| match known modifier names. There should have been explicit |
| prose to this effect, and some has been proposed as an erratum. |
| spec: 6.2/1 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e16.example.com |
| result: permerror |
| exp-twice: |
| description: | |
| exp= appears twice. |
| comment: >- |
| These two modifiers (exp,redirect) MUST NOT appear in a record more than |
| once each. If they do, then check_host() exits with a result of |
| "PermError". |
| spec: 6/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e14.example.com |
| result: permerror |
| redirect-empty-domain: |
| description: | |
| redirect = "redirect" "=" domain-spec |
| comment: >- |
| Unlike for exp, there is no instruction to override the permerror |
| for an empty domain-spec (which is invalid syntax). |
| spec: 6.2/4 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e18.example.com |
| result: permerror |
| redirect-twice: |
| description: | |
| redirect= appears twice. |
| comment: >- |
| These two modifiers (exp,redirect) MUST NOT appear in a record more than |
| once each. If they do, then check_host() exits with a result of |
| "PermError". |
| spec: 6/2 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e15.example.com |
| result: permerror |
| unknown-modifier-syntax: |
| description: | |
| unknown-modifier = name "=" macro-string |
| comment: >- |
| Unknown modifiers must have valid macro syntax. |
| spec: A/3 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e9.example.com |
| result: permerror |
| default-modifier-obsolete: |
| description: | |
| Unknown modifiers do not modify the RFC SPF result. |
| comment: >- |
| Some implementations may have a leftover default= modifier from |
| earlier drafts. |
| spec: 6/3 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e19.example.com |
| result: neutral |
| default-modifier-obsolete2: |
| description: | |
| Unknown modifiers do not modify the RFC SPF result. |
| comment: >- |
| Some implementations may have a leftover default= modifier from |
| earlier drafts. |
| spec: 6/3 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e20.example.com |
| result: neutral |
| zonedata: |
| mail.example.com: |
| - A: 1.2.3.4 |
| e1.example.com: |
| - SPF: v=spf1 exp=exp1.example.com redirect=e2.example.com |
| e2.example.com: |
| - SPF: v=spf1 -all |
| e3.example.com: |
| - SPF: v=spf1 exp=exp1.example.com redirect=e4.example.com |
| e4.example.com: |
| - SPF: v=spf1 -all exp=exp2.example.com |
| exp1.example.com: |
| - TXT: No-see-um |
| exp2.example.com: |
| - TXT: See me. |
| exp3.example.com: |
| - TXT: Correct! |
| exp4.example.com: |
| - TXT: "%{l} in implementation" |
| e5.example.com: |
| - SPF: v=spf1 1up=foo |
| e6.example.com: |
| - SPF: v=spf1 =all |
| e7.example.com: |
| - SPF: v=spf1 include:e3.example.com -all exp=exp3.example.com |
| e8.example.com: |
| - SPF: v=spf1 -all exp=exp4.example.com |
| e9.example.com: |
| - SPF: v=spf1 -all foo=%abc |
| e10.example.com: |
| - SPF: v=spf1 redirect=erehwon.example.com |
| e11.example.com: |
| - SPF: v=spf1 -all exp=e11msg.example.com |
| e11msg.example.com: |
| - TXT: Answer a fool according to his folly. |
| - TXT: Do not answer a fool according to his folly. |
| e12.example.com: |
| - SPF: v=spf1 exp= -all |
| e13.example.com: |
| - SPF: v=spf1 exp=e13msg.example.com -all |
| e13msg.example.com: |
| - TXT: The %{x}-files. |
| e14.example.com: |
| - SPF: v=spf1 exp=e13msg.example.com -all exp=e11msg.example.com |
| e15.example.com: |
| - SPF: v=spf1 redirect=e12.example.com -all redirect=e12.example.com |
| e16.example.com: |
| - SPF: v=spf1 exp=-all |
| e17.example.com: |
| - SPF: v=spf1 redirect=-all ?all |
| e18.example.com: |
| - SPF: v=spf1 ?all redirect= |
| e19.example.com: |
| - SPF: v=spf1 default=pass |
| e20.example.com: |
| - SPF: "v=spf1 default=+" |
| e21.example.com: |
| - SPF: v=spf1 exp=e21msg.example.com -all |
| e21msg.example.com: |
| - TIMEOUT |
| e22.example.com: |
| - SPF: v=spf1 exp=mail.example.com -all |
| --- |
| description: Macro expansion rules |
| tests: |
| trailing-dot-domain: |
| spec: 8.1/16 |
| description: >- |
| trailing dot is ignored for domains |
| helo: msgbas2x.cos.example.com |
| host: 192.168.218.40 |
| mailfrom: test@example.com |
| result: pass |
| trailing-dot-exp: |
| spec: 8.1 |
| description: >- |
| trailing dot is not removed from explanation |
| comment: >- |
| A simple way for an implementation to ignore trailing dots on |
| domains is to remove it when present. But be careful not to |
| remove it for explanation text. |
| helo: msgbas2x.cos.example.com |
| host: 192.168.218.40 |
| mailfrom: test@exp.example.com |
| result: fail |
| explanation: This is a test. |
| exp-only-macro-char: |
| spec: 8.1/8 |
| description: >- |
| The following macro letters are allowed only in "exp" text: c, r, t |
| helo: msgbas2x.cos.example.com |
| host: 192.168.218.40 |
| mailfrom: test@e2.example.com |
| result: permerror |
| invalid-macro-char: |
| spec: 8.1/9 |
| description: >- |
| A '%' character not followed by a '{', '%', '-', or '_' character |
| is a syntax error. |
| helo: msgbas2x.cos.example.com |
| host: 192.168.218.40 |
| mailfrom: test@e1.example.com |
| result: permerror |
| exp-txt-macro-char: |
| spec: 8.1/20 |
| description: >- |
| For IPv4 addresses, both the "i" and "c" macros expand |
| to the standard dotted-quad format. |
| helo: msgbas2x.cos.example.com |
| host: 192.168.218.40 |
| mailfrom: test@e3.example.com |
| result: fail |
| explanation: Connections from 192.168.218.40 not authorized. |
| domain-name-truncation: |
| spec: 8.1/25 |
| description: >- |
| When the result of macro expansion is used in a domain name query, if the |
| expanded domain name exceeds 253 characters, the left side is truncated |
| to fit, by removing successive domain labels until the total length does |
| not exceed 253 characters. |
| helo: msgbas2x.cos.example.com |
| host: 192.168.218.40 |
| mailfrom: test@somewhat.long.exp.example.com |
| result: fail |
| explanation: Congratulations! That was tricky. |
| v-macro-ip4: |
| spec: 8.1/6 |
| description: |- |
| v = the string "in-addr" if <ip> is ipv4, or "ip6" if <ip> is ipv6 |
| helo: msgbas2x.cos.example.com |
| host: 192.168.218.40 |
| mailfrom: test@e4.example.com |
| result: fail |
| explanation: 192.168.218.40 is queried as 40.218.168.192.in-addr.arpa |
| v-macro-ip6: |
| spec: 8.1/6 |
| description: |- |
| v = the string "in-addr" if <ip> is ipv4, or "ip6" if <ip> is ipv6 |
| helo: msgbas2x.cos.example.com |
| host: CAFE:BABE::1 |
| mailfrom: test@e4.example.com |
| result: fail |
| explanation: cafe:babe::1 is queried as 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.E.B.A.B.E.F.A.C.ip6.arpa |
| undef-macro: |
| spec: 8.1/6 |
| description: >- |
| Allowed macros chars are 'slodipvh' plus 'crt' in explanation. |
| helo: msgbas2x.cos.example.com |
| host: CAFE:BABE::192.168.218.40 |
| mailfrom: test@e5.example.com |
| result: permerror |
| p-macro-ip4-novalid: |
| spec: 8.1/22 |
| description: |- |
| p = the validated domain name of <ip> |
| comment: >- |
| The PTR in this example does not validate. |
| helo: msgbas2x.cos.example.com |
| host: 192.168.218.40 |
| mailfrom: test@e6.example.com |
| result: fail |
| explanation: connect from unknown |
| p-macro-ip4-valid: |
| spec: 8.1/22 |
| description: |- |
| p = the validated domain name of <ip> |
| comment: >- |
| If a subdomain of the <domain> is present, it SHOULD be used. |
| helo: msgbas2x.cos.example.com |
| host: 192.168.218.41 |
| mailfrom: test@e6.example.com |
| result: fail |
| explanation: connect from mx.example.com |
| p-macro-ip6-novalid: |
| spec: 8.1/22 |
| description: |- |
| p = the validated domain name of <ip> |
| comment: >- |
| The PTR in this example does not validate. |
| helo: msgbas2x.cos.example.com |
| host: CAFE:BABE::1 |
| mailfrom: test@e6.example.com |
| result: fail |
| explanation: connect from unknown |
| p-macro-ip6-valid: |
| spec: 8.1/22 |
| description: |- |
| p = the validated domain name of <ip> |
| comment: >- |
| If a subdomain of the <domain> is present, it SHOULD be used. |
| helo: msgbas2x.cos.example.com |
| host: CAFE:BABE::3 |
| mailfrom: test@e6.example.com |
| result: fail |
| explanation: connect from mx.example.com |
| p-macro-multiple: |
| spec: 8.1/22 |
| description: |- |
| p = the validated domain name of <ip> |
| comment: >- |
| If a subdomain of the <domain> is present, it SHOULD be used. |
| helo: msgbas2x.cos.example.com |
| host: 192.168.218.42 |
| mailfrom: test@e7.example.com |
| result: [pass, softfail] |
| upper-macro: |
| spec: 8.1/26 |
| description: >- |
| Uppercased macros expand exactly as their lowercased equivalents, |
| and are then URL escaped. |
| helo: msgbas2x.cos.example.com |
| host: 192.168.218.42 |
| mailfrom: jack&jill=up@e8.example.com |
| result: fail |
| explanation: http://example.com/why.html?l=jack%26jill%3Dup |
| hello-macro: |
| spec: 8.1/6 |
| description: |- |
| h = HELO/EHLO domain |
| helo: msgbas2x.cos.example.com |
| host: 192.168.218.40 |
| mailfrom: test@e9.example.com |
| result: pass |
| invalid-hello-macro: |
| spec: 8.1/2 |
| description: |- |
| h = HELO/EHLO domain, but HELO is invalid |
| comment: >- |
| Domain-spec must end in either a macro, or a valid toplabel. |
| It is not correct to check syntax after macro expansion. |
| helo: "JUMPIN' JUPITER" |
| host: 192.168.218.40 |
| mailfrom: test@e9.example.com |
| result: fail |
| hello-domain-literal: |
| spec: 8.1/2 |
| description: |- |
| h = HELO/EHLO domain, but HELO is a domain literal |
| comment: >- |
| Domain-spec must end in either a macro, or a valid toplabel. |
| It is not correct to check syntax after macro expansion. |
| helo: "[192.168.218.40]" |
| host: 192.168.218.40 |
| mailfrom: test@e9.example.com |
| result: fail |
| require-valid-helo: |
| spec: 8.1/6 |
| description: >- |
| Example of requiring valid helo in sender policy. This is a complex |
| policy testing several points at once. |
| helo: OEMCOMPUTER |
| host: 1.2.3.4 |
| mailfrom: test@e10.example.com |
| result: fail |
| macro-reverse-split-on-dash: |
| spec: [8.1/15, 8.1/16, 8.1/17, 8.1/18] |
| description: >- |
| Macro value transformation (splitting on arbitrary characters, reversal, |
| number of right-hand parts to use) |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: philip-gladstone-test@e11.example.com |
| result: pass |
| zonedata: |
| example.com.d.spf.example.com: |
| - SPF: v=spf1 redirect=a.spf.example.com |
| a.spf.example.com: |
| - SPF: v=spf1 include:o.spf.example.com. ~all |
| o.spf.example.com: |
| - SPF: v=spf1 ip4:192.168.218.40 |
| msgbas2x.cos.example.com: |
| - A: 192.168.218.40 |
| example.com: |
| - A: 192.168.90.76 |
| - SPF: v=spf1 redirect=%{d}.d.spf.example.com. |
| exp.example.com: |
| - SPF: v=spf1 exp=msg.example.com. -all |
| msg.example.com: |
| - TXT: This is a test. |
| e1.example.com: |
| - SPF: v=spf1 -exists:%(ir).sbl.example.com ?all |
| e2.example.com: |
| - SPF: v=spf1 -all exp=%{r}.example.com |
| e3.example.com: |
| - SPF: v=spf1 -all exp=%{ir}.example.com |
| 40.218.168.192.example.com: |
| - TXT: Connections from %{c} not authorized. |
| somewhat.long.exp.example.com: |
| - SPF: v=spf1 -all exp=foobar.%{o}.%{o}.%{o}.%{o}.%{o}.%{o}.%{o}.%{o}.example.com |
| somewhat.long.exp.example.com.somewhat.long.exp.example.com.somewhat.long.exp.example.com.somewhat.long.exp.example.com.somewhat.long.exp.example.com.somewhat.long.exp.example.com.somewhat.long.exp.example.com.somewhat.long.exp.example.com.example.com: |
| - TXT: Congratulations! That was tricky. |
| e4.example.com: |
| - SPF: v=spf1 -all exp=e4msg.example.com |
| e4msg.example.com: |
| - TXT: "%{c} is queried as %{ir}.%{v}.arpa" |
| e5.example.com: |
| - SPF: v=spf1 a:%{a}.example.com -all |
| e6.example.com: |
| - SPF: v=spf1 -all exp=e6msg.example.com |
| e6msg.example.com: |
| - TXT: "connect from %{p}" |
| mx.example.com: |
| - A: 192.168.218.41 |
| - A: 192.168.218.42 |
| - AAAA: CAFE:BABE::2 |
| - AAAA: CAFE:BABE::3 |
| 40.218.168.192.in-addr.arpa: |
| - PTR: mx.example.com |
| 41.218.168.192.in-addr.arpa: |
| - PTR: mx.example.com |
| 42.218.168.192.in-addr.arpa: |
| - PTR: mx.example.com |
| - PTR: mx.e7.example.com |
| 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.E.B.A.B.E.F.A.C.ip6.arpa: |
| - PTR: mx.example.com |
| 3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.E.B.A.B.E.F.A.C.ip6.arpa: |
| - PTR: mx.example.com |
| mx.e7.example.com: |
| - A: 192.168.218.42 |
| mx.e7.example.com.should.example.com: |
| - A: 127.0.0.2 |
| mx.example.com.ok.example.com: |
| - A: 127.0.0.2 |
| e7.example.com: |
| - SPF: v=spf1 exists:%{p}.should.example.com ~exists:%{p}.ok.example.com |
| e8.example.com: |
| - SPF: v=spf1 -all exp=msg8.%{D2} |
| msg8.example.com: |
| - TXT: "http://example.com/why.html?l=%{L}" |
| e9.example.com: |
| - SPF: v=spf1 a:%{H} -all |
| e10.example.com: |
| - SPF: v=spf1 -include:_spfh.%{d2} ip4:1.2.3.0/24 -all |
| _spfh.example.com: |
| - SPF: v=spf1 -a:%{h} +all |
| e11.example.com: |
| - SPF: v=spf1 exists:%{i}.%{l2r-}.user.%{d2} |
| 1.2.3.4.gladstone.philip.user.example.com: |
| - A: 127.0.0.2 |
| --- |
| description: Processing limits |
| tests: |
| redirect-loop: |
| description: >- |
| SPF implementations MUST limit the number of mechanisms and modifiers |
| that do DNS lookups to at most 10 per SPF check. |
| spec: 10.1/6 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e1.example.com |
| result: permerror |
| include-loop: |
| description: >- |
| SPF implementations MUST limit the number of mechanisms and modifiers |
| that do DNS lookups to at most 10 per SPF check. |
| spec: 10.1/6 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e2.example.com |
| result: permerror |
| mx-limit: |
| description: >- |
| there MUST be a limit of no more than 10 MX looked up and checked. |
| comment: >- |
| The required result for this test was the subject of much |
| controversy. Many felt that the RFC *should* have specified |
| permerror, but the consensus was that it failed to actually do so. |
| The preferred result reflects evaluating the 10 allowed MX records in the |
| order returned by the test data - or sorted via priority. |
| If testing with live DNS, the MX order may be random, and a pass |
| result would still be compliant. The SPF result is effectively |
| random. |
| spec: 10.1/7 |
| helo: mail.example.com |
| host: 1.2.3.5 |
| mailfrom: foo@e4.example.com |
| result: [neutral, pass] |
| ptr-limit: |
| description: >- |
| there MUST be a limit of no more than 10 PTR looked up and checked. |
| comment: >- |
| The result of this test cannot be permerror not only because the |
| RFC does not specify it, but because the sender has no control over |
| the PTR records of spammers. |
| The preferred result reflects evaluating the 10 allowed PTR records in |
| the order returned by the test data. |
| If testing with live DNS, the PTR order may be random, and a pass |
| result would still be compliant. The SPF result is effectively |
| randomized. |
| spec: 10.1/7 |
| helo: mail.example.com |
| host: 1.2.3.5 |
| mailfrom: foo@e5.example.com |
| result: [neutral, pass] |
| false-a-limit: |
| description: >- |
| unlike MX, PTR, there is no RR limit for A |
| comment: >- |
| There seems to be a tendency for developers to want to limit |
| A RRs in addition to MX and PTR. These are IPs, not usable for |
| 3rd party DoS attacks, and hence need no low limit. |
| spec: 10.1/7 |
| helo: mail.example.com |
| host: 1.2.3.12 |
| mailfrom: foo@e10.example.com |
| result: pass |
| mech-at-limit: |
| description: >- |
| SPF implementations MUST limit the number of mechanisms and modifiers |
| that do DNS lookups to at most 10 per SPF check. |
| spec: 10.1/6 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e6.example.com |
| result: pass |
| mech-over-limit: |
| description: >- |
| SPF implementations MUST limit the number of mechanisms and modifiers |
| that do DNS lookups to at most 10 per SPF check. |
| comment: >- |
| We do not check whether an implementation counts mechanisms before |
| or after evaluation. The RFC is not clear on this. |
| spec: 10.1/6 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e7.example.com |
| result: permerror |
| include-at-limit: |
| description: >- |
| SPF implementations MUST limit the number of mechanisms and modifiers |
| that do DNS lookups to at most 10 per SPF check. |
| comment: >- |
| The part of the RFC that talks about MAY parse the entire record first |
| (4.6) is specific to syntax errors. Processing limits is a different, |
| non-syntax issue. Processing limits (10.1) specifically talks about |
| limits during a check. |
| spec: 10.1/6 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e8.example.com |
| result: pass |
| include-over-limit: |
| description: >- |
| SPF implementations MUST limit the number of mechanisms and modifiers |
| that do DNS lookups to at most 10 per SPF check. |
| spec: 10.1/6 |
| helo: mail.example.com |
| host: 1.2.3.4 |
| mailfrom: foo@e9.example.com |
| result: permerror |
| zonedata: |
| mail.example.com: |
| - A: 1.2.3.4 |
| e1.example.com: |
| - SPF: v=spf1 ip4:1.1.1.1 redirect=e1.example.com |
| e2.example.com: |
| - SPF: v=spf1 include:e3.example.com |
| e3.example.com: |
| - SPF: v=spf1 include:e2.example.com |
| e4.example.com: |
| - SPF: v=spf1 mx |
| - MX: [0, mail.example.com] |
| - MX: [1, mail.example.com] |
| - MX: [2, mail.example.com] |
| - MX: [3, mail.example.com] |
| - MX: [4, mail.example.com] |
| - MX: [5, mail.example.com] |
| - MX: [6, mail.example.com] |
| - MX: [7, mail.example.com] |
| - MX: [8, mail.example.com] |
| - MX: [9, mail.example.com] |
| - MX: [10, e4.example.com] |
| - A: 1.2.3.5 |
| e5.example.com: |
| - SPF: v=spf1 ptr |
| - A: 1.2.3.5 |
| 5.3.2.1.in-addr.arpa: |
| - PTR: e1.example.com. |
| - PTR: e2.example.com. |
| - PTR: e3.example.com. |
| - PTR: e4.example.com. |
| - PTR: example.com. |
| - PTR: e6.example.com. |
| - PTR: e7.example.com. |
| - PTR: e8.example.com. |
| - PTR: e9.example.com. |
| - PTR: e10.example.com. |
| - PTR: e5.example.com. |
| e6.example.com: |
| - SPF: v=spf1 a mx a mx a mx a mx a ptr ip4:1.2.3.4 -all |
| e7.example.com: |
| - SPF: v=spf1 a mx a mx a mx a mx a ptr a ip4:1.2.3.4 -all |
| e8.example.com: |
| - SPF: v=spf1 a include:inc.example.com ip4:1.2.3.4 mx -all |
| inc.example.com: |
| - SPF: v=spf1 a a a a a a a a |
| e9.example.com: |
| - SPF: v=spf1 a include:inc.example.com a ip4:1.2.3.4 -all |
| e10.example.com: |
| - SPF: v=spf1 a -all |
| - A: 1.2.3.1 |
| - A: 1.2.3.2 |
| - A: 1.2.3.3 |
| - A: 1.2.3.4 |
| - A: 1.2.3.5 |
| - A: 1.2.3.6 |
| - A: 1.2.3.7 |
| - A: 1.2.3.8 |
| - A: 1.2.3.9 |
| - A: 1.2.3.10 |
| - A: 1.2.3.11 |
| - A: 1.2.3.12 |