Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
mailrs-shield
SMTP server anti-spam primitives in three modules: DNSBL lookups, greylisting policy, and FCrDNS (forward-confirmed reverse DNS) checks — async, transport-agnostic, mostly zero-I/O.
Extracted from mailrs so any Rust mail server can drop these in without re-implementing the same DNS-walking patterns. The Rust ecosystem currently has no dedicated crates for any of these three primitives.
What's inside
shield::dnsbl — DNS blocklist queries
Look up an inbound client IP against zones like Spamhaus ZEN, Barracuda, etc. Comes with an in-process TTL cache so repeat connections don't re-query.
use TokioResolver;
use check_dnsbl;
use IpAddr;
# async
shield::greylist — Greylisting policy
Pure policy (Harris 2003 / RFC 6647): defer the first time you see a (client_ip, sender, recipient) triplet, accept after the configured delay if the sender retries. Legitimate MTAs queue and retry; most spam bots don't.
use ;
let cfg = default; // 5-minute initial delay, 36-day pass window
assert_eq!;
assert_eq!;
assert_eq!;
GreylistDb runs the policy over a pluggable GreylistBackend behind a single check() call. The default kevy-store feature ships an in-process kevy backend:
#
#
To plug in your own store, implement GreylistBackend (get, set_with_ttl, expire — three key-value operations), build the store with GreylistDb::with_backend, and check the backend from a test with greylist::check_greylist_backend(&backend).await. With default-features = false, features = ["store"] the crate has no storage dependency at all.
shield::ptr — FCrDNS check
Score an inbound client by whether its IP's reverse DNS forward-resolves back to a name matching the EHLO domain. Returns 0.0 on full match, 1.0 on no match — easy to fold into a spam score.
use TokioResolver;
use check_client_ptr;
use IpAddr;
# async
Performance
Microbenchmarks for the pure helpers (no live resolver hits) live in benches/ops.rs. Measured with criterion 0.8 on Apple Silicon (M-series), cargo bench, release profile.
| Operation | Median | Notes |
|---|---|---|
dnsbl::reverse_ipv4(1.2.3.4) |
~110 ns | builds the 4.3.2.1.zen.spamhaus.org.-shape name |
dnsbl::interpret_spamhaus(127.0.0.2) |
~700 ps | match-arm dispatch, no allocation |
greylist::evaluate_triplet(first seen) |
~850 ps | always defers |
greylist::evaluate_triplet(retry within delay) |
~1.5 ns | timestamp delta + comparison |
greylist::triplet_key(ip, sender, rcpt) |
~120 ns | one format! + lowercase normalization |
ptr::ptr_score_from_names(match) |
~85 ns | scans the candidate names for the EHLO domain |
ptr::ptr_score_from_names(no match) |
~200 ns | runs the full FCrDNS scoring fallback |
Live-resolver paths (check_client_ptr, dnsbl::check, greylist::GreylistDb::check) aren't bench-able offline; production latency is dominated by DNS round-trips on the resolver paths. With the in-process kevy backend the GreylistDb store path makes no network call.
Run with cargo bench -p mailrs-shield. See tests/perf_gate.rs for the regression budgets.
Feature flags
| Flag | Default | What it enables |
|---|---|---|
store |
via kevy-store |
greylist::GreylistDb, the GreylistBackend trait and check_greylist_backend |
kevy-store |
yes | store + greylist::EmbeddedGreylistBackend (in-process kevy) |
Use default-features = false, features = ["store"] when you bring your own backend.
License
Licensed under either of Apache License 2.0 or MIT license at your option.