#spf #email #smtp #dns #domain


Implementation of the Sender Policy Framework (SPF) protocol

12 unstable releases (4 breaking)

new 0.4.0-alpha.2 Oct 18, 2021
0.4.0-alpha.1 Jul 2, 2021
0.3.2 Oct 18, 2021
0.3.1 Mar 10, 2021
0.0.2 Jul 4, 2020

#12 in Email

Download history 12/week @ 2021-07-03 22/week @ 2021-07-10 82/week @ 2021-07-17 31/week @ 2021-07-24 168/week @ 2021-07-31 27/week @ 2021-08-07 39/week @ 2021-08-14 16/week @ 2021-08-21 10/week @ 2021-08-28 2/week @ 2021-09-04 17/week @ 2021-09-11 7/week @ 2021-09-18 1/week @ 2021-09-25 22/week @ 2021-10-02 26/week @ 2021-10-09 42/week @ 2021-10-16

130 downloads per month
Used in 4 crates (2 directly)


4.5K SLoC


The viaspf library is a complete implementation of the Sender Policy Framework (SPF) protocol, version 1, as specified in RFC 7208. It is written in the Rust programming language.

This library implements the core SPF protocol, but it does not itself do DNS queries and it does not depend on a DNS library. Users of this library must provide an implementation of a DNS lookup trait in order to perform SPF queries. That way, we hope to enable users to choose themselves which DNS resolver they want to use to implement their SPF verifier applications.

This library was first created in a ‘clean room’ setting. That is, it was written from scratch, referring only to the RFC, and following it to the letter. It can therefore be considered an independent alternative to existing SPF protocol implementations.

The minimum supported Rust version is 1.45.0.


This is a Rust library, for consumption through Cargo as usual.

Note: A preliminary async version of the API can be found on the 0.4.0 branch (alpha).

The main purpose of the viaspf library is SPF verification, that is, checking whether a sending host is authorised to use some mail domain according to published SPF policy. For this end, this library provides the function evaluate_spf as the main API item. The function signature is as follows:

async fn evaluate_spf(
    lookup: &(impl Lookup + Send + Sync),
    config: &Config,
    ip: IpAddr,
    sender: &str,
    helo_domain: &str,
) -> QueryResult;

Refer to the API documentation for a full description of the inputs and output, and suggested usage patterns.

The first argument, lookup, deserves brief elaboration. While viaspf contains a complete implementation of the SPF protocol, it does not itself include DNS resolution capabilities (which are, after all, a core component of SPF). Instead, DNS resolution is abstracted into the trait Lookup, and is thus ‘pluggable’. evaluate_spf requires to be passed an implementation of this trait, which it will then use as a DNS resolver through which all DNS queries are conducted.

As a convenience, the Cargo feature trust-dns-resolver can be enabled to make an implementation of Lookup available for the Trust-DNS resolver.

Note that it is also possible to forgo the SPF evaluation functionality and only use the library’s data model. The data structures in viaspf::record constitute a faithful encoding of the grammar in section 12 of RFC 7208, and are mostly decoupled from evaluation.

Finally, we point again to the API documentation, which describes additional functionality, such as capturing a trace of the query execution. The trace provides programmatic access to the protocol processing steps after the fact.


A simple SPF verifier is included as an executable example: the command-line tool spfquery. This program uses the Trust-DNS resolver to perform DNS lookups.

Pass an IP address and a domain name as arguments to spfquery. The query is then evaluated and the result and a trace is printed out.

cargo run --features trust-dns-resolver \
  --example spfquery -- gluet.ch
Domain: gluet.ch
SPF result: pass
Mechanism: mx
  executing SPF query for domain "gluet.ch"
  looking up TXT records for "gluet.ch"
  evaluating SPF record "v=spf1 mx -all"
  evaluating directive "mx"
  evaluating mechanism "mx"
  incrementing global lookup count
  using target name "gluet.ch"
  looking up MX records for "gluet.ch"
  trying MX name "mail.gluet.ch"
  incrementing global lookup count
  looking up A records for "mail.gluet.ch"
  trying IP address
  incrementing per-mechanism lookup count
  mechanism matched
  evaluated directive to result "pass"


Copyright © 2020–2021 David Bürgin

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.


~64K SLoC