Parses SPF records (RFC 7208 §4.5, §12).
iex> Sovite.SPF.Record.parse("v=spf1 ip4:192.0.2.0/24 -all")
{:ok, [{:pass, {:ip4, {192, 0, 2, 0}, 24}, "ip4:192.0.2.0/24"}, {:fail, :all, "-all"}]}The whole record is parsed before it is evaluated, so a syntax error anywhere makes it unusable, as the RFC requires. Mechanism and modifier names are matched against fixed tables, so a record never creates atoms.
A record parses to a list of terms in record order:
- directives,
{qualifier, mechanism, text}, wheretextis the term as written; {:redirect, domain_spec}and{:exp, domain_spec}modifiers.
Unknown modifiers are checked for syntax and then left out.
Summary
Functions
Parses an SPF record into its terms.
Returns true if the TXT record text is an SPF record: it starts
with v=spf1, followed by a space or nothing (RFC 7208 §4.5).
Types
@type cidr() :: {0..32, 0..128}
IPv4 and IPv6 prefix lengths for a and mx.
@type mechanism() :: :all | {:include, Sovite.SPF.Macro.t()} | {:a, Sovite.SPF.Macro.t() | nil, cidr()} | {:mx, Sovite.SPF.Macro.t() | nil, cidr()} | {:ptr, Sovite.SPF.Macro.t() | nil} | {:ip4, :inet.ip4_address(), 0..32} | {:ip6, :inet.ip6_address(), 0..128} | {:exists, Sovite.SPF.Macro.t()}
@type modifier() :: {:redirect, Sovite.SPF.Macro.t()} | {:exp, Sovite.SPF.Macro.t()}
@type qualifier() :: :pass | :fail | :softfail | :neutral
What a matching directive returns.
Functions
Parses an SPF record into its terms.
iex> Sovite.SPF.Record.parse("v=spf1 a:%{d}/24//64 redirect=_spf.example.com")
{:ok,
[
{:pass, {:a, [{:macro, :d, nil, false, [], false}], {24, 64}}, "a:%{d}/24//64"},
{:redirect, ["_spf.example.com"]}
]}
iex> Sovite.SPF.Record.parse("v=spf1 ip4:192.0.2.1/33")
{:error, ~s(invalid term "ip4:192.0.2.1/33")}
Returns true if the TXT record text is an SPF record: it starts
with v=spf1, followed by a space or nothing (RFC 7208 §4.5).
iex> Sovite.SPF.Record.spf?("v=spf1 -all")
true
iex> Sovite.SPF.Record.spf?("v=spf10")
false