Crates.io | mail-auth |
lib.rs | mail-auth |
version | 0.5.0 |
source | src |
created_at | 2022-12-01 15:10:11.530404 |
updated_at | 2024-08-11 18:03:29.025545 |
description | DKIM, ARC, SPF and DMARC library for Rust |
homepage | https://github.com/stalwartlabs/mail-auth |
repository | https://github.com/stalwartlabs/mail-auth |
max_upload_size | |
id | 727677 |
size | 779,529 |
mail-auth is an e-mail authentication and reporting library written in Rust that supports the DKIM, ARC, SPF and DMARC protocols. The library aims to be fast, safe and correct while supporting all major message authentication and reporting RFCs.
Features:
generate
feature). // Create a resolver using Cloudflare DNS
let resolver = Resolver::new_cloudflare_tls().unwrap();
// Parse message
let authenticated_message = AuthenticatedMessage::parse(RFC5322_MESSAGE.as_bytes()).unwrap();
// Validate signature
let result = resolver.verify_dkim(&authenticated_message).await;
// Make sure all signatures passed verification
assert!(result.iter().all(|s| s.result() == &DkimResult::Pass));
// Sign an e-mail message using RSA-SHA256
let pk_rsa = RsaKey::<Sha256>::from_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
let signature_rsa = DkimSigner::from_key(pk_rsa)
.domain("example.com")
.selector("default")
.headers(["From", "To", "Subject"])
.sign(RFC5322_MESSAGE.as_bytes())
.unwrap();
// Sign an e-mail message using ED25519-SHA256
let pk_ed = Ed25519Key::from_bytes(
&base64_decode(ED25519_PUBLIC_KEY.as_bytes()).unwrap(),
&base64_decode(ED25519_PRIVATE_KEY.as_bytes()).unwrap(),
)
.unwrap();
let signature_ed = DkimSigner::from_key(pk_ed)
.domain("example.com")
.selector("default-ed")
.headers(["From", "To", "Subject"])
.sign(RFC5322_MESSAGE.as_bytes())
.unwrap();
// Print the message including both signatures to stdout
println!(
"{}{}{}",
signature_rsa.to_header(),
signature_ed.to_header(),
RFC5322_MESSAGE
);
// Create a resolver using Cloudflare DNS
let resolver = Resolver::new_cloudflare_tls().unwrap();
// Parse message
let authenticated_message = AuthenticatedMessage::parse(RFC5322_MESSAGE.as_bytes()).unwrap();
// Validate ARC chain
let result = resolver.verify_arc(&authenticated_message).await;
// Make sure ARC passed verification
assert_eq!(result.result(), &DkimResult::Pass);
// Create a resolver using Cloudflare DNS
let resolver = Resolver::new_cloudflare_tls().unwrap();
// Parse message to be sealed
let authenticated_message = AuthenticatedMessage::parse(RFC5322_MESSAGE.as_bytes()).unwrap();
// Verify ARC and DKIM signatures
let arc_result = resolver.verify_arc(&authenticated_message).await;
let dkim_result = resolver.verify_dkim(&authenticated_message).await;
// Build Authenticated-Results header
let auth_results = AuthenticationResults::new("mx.mydomain.org")
.with_dkim_result(&dkim_result, "sender@example.org")
.with_arc_result(&arc_result, "127.0.0.1".parse().unwrap());
// Seal message
if arc_result.can_be_sealed() {
// Seal the e-mail message using RSA-SHA256
let pk_rsa = RsaKey::<Sha256>::from_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
let arc_set = ArcSealer::from_key(pk_rsa)
.domain("example.org")
.selector("default")
.headers(["From", "To", "Subject", "DKIM-Signature"])
.seal(&authenticated_message, &auth_results, &arc_result)
.unwrap();
// Print the sealed message to stdout
println!("{}{}", arc_set.to_header(), RFC5322_MESSAGE)
} else {
eprintln!("The message could not be sealed, probably an ARC chain with cv=fail was found.")
}
// Create a resolver using Cloudflare DNS
let resolver = Resolver::new_cloudflare_tls().unwrap();
// Verify HELO identity
let result = resolver
.verify_spf_helo("127.0.0.1".parse().unwrap(), "gmail.com", "my-local-domain.org")
.await;
assert_eq!(result.result(), SpfResult::Fail);
// Verify MAIL-FROM identity
let result = resolver
.verify_spf_sender("::1".parse().unwrap(), "gmail.com", "my-local-domain.org", "sender@gmail.com")
.await;
assert_eq!(result.result(), SpfResult::Fail);
// Create a resolver using Cloudflare DNS
let resolver = Resolver::new_cloudflare_tls().unwrap();
// Verify DKIM signatures
let authenticated_message = AuthenticatedMessage::parse(RFC5322_MESSAGE.as_bytes()).unwrap();
let dkim_result = resolver.verify_dkim(&authenticated_message).await;
// Verify SPF MAIL-FROM identity
let spf_result = resolver
.verify_spf_sender("::1".parse().unwrap(), "example.org", "my-local-domain.org", "sender@example.org")
.await;
// Verify DMARC
let dmarc_result = resolver
.verify_dmarc(
&authenticated_message,
&dkim_result,
"example.org",
&spf_result,
|domain| psl::domain_str(domain).unwrap_or(domain),
)
.await;
assert_eq!(dmarc_result.dkim_result(), &DmarcResult::Pass);
assert_eq!(dmarc_result.spf_result(), &DmarcResult::Pass);
More examples available under the examples directory.
To run the testsuite:
$ cargo test
To fuzz the library with cargo-fuzz
:
$ cargo +nightly fuzz run mail_auth
Licensed under either of
at your option.
Copyright (C) 2020-2023, Stalwart Labs Ltd.