1package spf_test
2
3import (
4 "context"
5 "log"
6 "log/slog"
7 "net"
8
9 "github.com/mjl-/mox/dns"
10 "github.com/mjl-/mox/smtp"
11 "github.com/mjl-/mox/spf"
12)
13
14func ExampleVerify() {
15 ctx := context.Background()
16 resolver := dns.StrictResolver{}
17
18 args := spf.Args{
19 // IP from SMTP session.
20 RemoteIP: net.ParseIP("1.2.3.4"),
21
22 // Based on "MAIL FROM" in SMTP session.
23 MailFromLocalpart: smtp.Localpart("user"),
24 MailFromDomain: dns.Domain{ASCII: "sendingdomain.example.com"},
25
26 // From HELO/EHLO in SMTP session.
27 HelloDomain: dns.IPDomain{Domain: dns.Domain{ASCII: "mx.example.com"}},
28
29 // LocalIP and LocalHostname should be set, they may be used when evaluating macro's.
30 }
31
32 // Lookup SPF record and evaluate against IP and domain in args.
33 received, domain, explanation, authentic, err := spf.Verify(ctx, slog.Default(), resolver, args)
34
35 // received.Result is always set, regardless of err.
36 switch received.Result {
37 case spf.StatusNone:
38 log.Printf("no useful spf result, domain probably has no spf record")
39 case spf.StatusNeutral:
40 log.Printf("spf has no statement on ip, with \"?\" qualifier")
41 case spf.StatusPass:
42 log.Printf("ip is authorized")
43 case spf.StatusFail:
44 log.Printf("ip is not authorized, with \"-\" qualifier")
45 case spf.StatusSoftfail:
46 log.Printf("ip is probably not authorized, with \"~\" qualifier, softfail")
47 case spf.StatusTemperror:
48 log.Printf("temporary error, possibly dns lookup failure, try again soon")
49 case spf.StatusPermerror:
50 log.Printf("permanent error, possibly invalid spf records, later attempts likely have the same result")
51 }
52 if err != nil {
53 log.Printf("error: %v", err)
54 }
55 if explanation != "" {
56 log.Printf("explanation from remote about spf result: %s", explanation)
57 }
58 log.Printf("result is for domain %s", domain) // mailfrom or ehlo/ehlo.
59 log.Printf("dns lookups dnssec-protected: %v", authentic)
60}
61