Authentication Results
VaultSandbox validates email authentication for every received email, providing detailed SPF, DKIM, DMARC, and reverse DNS results.
What is Email Authentication?
Section titled “What is Email Authentication?”Email authentication helps verify that an email:
- Came from the claimed sender domain (SPF)
- Wasn’t modified in transit (DKIM)
- Complies with the domain’s policy (DMARC)
- Came from a legitimate mail server (Reverse DNS)
AuthResults Struct
Section titled “AuthResults Struct”Every email has an AuthResults field:
email, err := inbox.WaitForEmail(ctx, vaultsandbox.WithWaitTimeout(10*time.Second))if err != nil { log.Fatal(err)}
auth := email.AuthResults
fmt.Printf("SPF: %+v\n", auth.SPF)fmt.Printf("DKIM: %+v\n", auth.DKIM)fmt.Printf("DMARC: %+v\n", auth.DMARC)fmt.Printf("ReverseDNS: %+v\n", auth.ReverseDNS)The AuthResults struct is defined in the authresults package:
import "github.com/vaultsandbox/client-go/authresults"
type AuthResults struct { SPF *SPFResult DKIM []DKIMResult DMARC *DMARCResult ReverseDNS *ReverseDNSResult}SPF (Sender Policy Framework)
Section titled “SPF (Sender Policy Framework)”Verifies the sending server is authorized to send from the sender’s domain.
SPFResult Struct
Section titled “SPFResult Struct”type SPFResult struct { Result string // "pass", "fail", "softfail", "neutral", "none", "temperror", "permerror" Domain string IP string Info string}if email.AuthResults.SPF != nil { spf := email.AuthResults.SPF fmt.Printf("Result: %s\n", spf.Result) fmt.Printf("Domain: %s\n", spf.Domain) fmt.Printf("Info: %s\n", spf.Info)}SPF Status Values
Section titled “SPF Status Values”| Status | Meaning |
|---|---|
pass | Sending server is authorized |
fail | Sending server is NOT authorized |
softfail | Probably not authorized (policy says ~all) |
neutral | Domain makes no assertion |
temperror | Temporary error during check |
permerror | Permanent error in SPF record |
none | No SPF record found |
SPF Example
Section titled “SPF Example”email, err := inbox.WaitForEmail(ctx, vaultsandbox.WithWaitTimeout(10*time.Second))if err != nil { t.Fatal(err)}
if email.AuthResults.SPF != nil { spf := email.AuthResults.SPF
if spf.Result != "pass" { t.Errorf("expected SPF pass, got %s", spf.Result) } if spf.Domain != "example.com" { t.Errorf("expected domain example.com, got %s", spf.Domain) }
fmt.Printf("SPF %s for %s\n", spf.Result, spf.Domain)}DKIM (DomainKeys Identified Mail)
Section titled “DKIM (DomainKeys Identified Mail)”Cryptographically verifies the email hasn’t been modified and came from the claimed domain.
DKIMResult Struct
Section titled “DKIMResult Struct”type DKIMResult struct { Result string // "pass", "fail", "none" Domain string Selector string Info string}dkim := email.AuthResults.DKIM // []DKIMResult
if len(dkim) > 0 { for _, result := range dkim { fmt.Printf("Result: %s\n", result.Result) fmt.Printf("Domain: %s\n", result.Domain) fmt.Printf("Selector: %s\n", result.Selector) fmt.Printf("Info: %s\n", result.Info) }}Note: An email can have multiple DKIM signatures (one per signing domain).
DKIM Status Values
Section titled “DKIM Status Values”| Status | Meaning |
|---|---|
pass | Signature is valid |
fail | Signature is invalid |
none | No DKIM signature found |
DKIM Example
Section titled “DKIM Example”email, err := inbox.WaitForEmail(ctx, vaultsandbox.WithWaitTimeout(10*time.Second))if err != nil { t.Fatal(err)}
if len(email.AuthResults.DKIM) > 0 { dkim := email.AuthResults.DKIM[0]
if dkim.Result != "pass" { t.Errorf("expected DKIM pass, got %s", dkim.Result) } if dkim.Domain != "example.com" { t.Errorf("expected domain example.com, got %s", dkim.Domain) }
fmt.Printf("DKIM %s (%s._domainkey.%s)\n", dkim.Result, dkim.Selector, dkim.Domain)}DMARC (Domain-based Message Authentication)
Section titled “DMARC (Domain-based Message Authentication)”Checks that SPF or DKIM align with the From address and enforces the domain’s policy.
DMARCResult Struct
Section titled “DMARCResult Struct”type DMARCResult struct { Result string // "pass", "fail", "none" Policy string // "none", "quarantine", "reject" Aligned bool Domain string Info string}if email.AuthResults.DMARC != nil { dmarc := email.AuthResults.DMARC fmt.Printf("Result: %s\n", dmarc.Result) fmt.Printf("Domain: %s\n", dmarc.Domain) fmt.Printf("Policy: %s\n", dmarc.Policy) fmt.Printf("Aligned: %v\n", dmarc.Aligned) fmt.Printf("Info: %s\n", dmarc.Info)}DMARC Status Values
Section titled “DMARC Status Values”| Status | Meaning |
|---|---|
pass | DMARC check passed (SPF or DKIM aligned) |
fail | DMARC check failed |
none | No DMARC policy found |
DMARC Policies
Section titled “DMARC Policies”| Policy | Meaning |
|---|---|
none | No action (monitoring only) |
quarantine | Treat suspicious emails as spam |
reject | Reject emails that fail DMARC |
DMARC Example
Section titled “DMARC Example”email, err := inbox.WaitForEmail(ctx, vaultsandbox.WithWaitTimeout(10*time.Second))if err != nil { t.Fatal(err)}
if email.AuthResults.DMARC != nil { dmarc := email.AuthResults.DMARC
if dmarc.Result != "pass" { t.Errorf("expected DMARC pass, got %s", dmarc.Result) } if dmarc.Domain != "example.com" { t.Errorf("expected domain example.com, got %s", dmarc.Domain) }
fmt.Printf("DMARC %s (policy: %s)\n", dmarc.Result, dmarc.Policy)}Reverse DNS
Section titled “Reverse DNS”Verifies the sending server’s IP resolves to a hostname that matches the sending domain.
ReverseDNSResult Struct
Section titled “ReverseDNSResult Struct”type ReverseDNSResult struct { Verified bool // true if reverse DNS verified IP string Hostname string Info string}if email.AuthResults.ReverseDNS != nil { rdns := email.AuthResults.ReverseDNS fmt.Printf("Verified: %v\n", rdns.Verified) fmt.Printf("IP: %s\n", rdns.IP) fmt.Printf("Hostname: %s\n", rdns.Hostname) fmt.Printf("Info: %s\n", rdns.Info)}Reverse DNS Verified Values
Section titled “Reverse DNS Verified Values”| Verified | Meaning |
|---|---|
true | Reverse DNS verified |
false | Reverse DNS failed |
Reverse DNS Example
Section titled “Reverse DNS Example”email, err := inbox.WaitForEmail(ctx, vaultsandbox.WithWaitTimeout(10*time.Second))if err != nil { t.Fatal(err)}
if email.AuthResults.ReverseDNS != nil { rdns := email.AuthResults.ReverseDNS
fmt.Printf("Reverse DNS: %s -> %s\n", rdns.IP, rdns.Hostname) fmt.Printf("Verified: %v\n", rdns.Verified)}Validation Methods
Section titled “Validation Methods”Validate Method
Section titled “Validate Method”The Validate() method provides a summary of all authentication checks:
validation := email.AuthResults.Validate()
fmt.Printf("Passed: %v\n", validation.Passed)fmt.Printf("SPF Passed: %v\n", validation.SPFPassed)fmt.Printf("DKIM Passed: %v\n", validation.DKIMPassed)fmt.Printf("DMARC Passed: %v\n", validation.DMARCPassed)fmt.Printf("ReverseDNS Passed: %v\n", validation.ReverseDNSPassed)fmt.Printf("Failures: %v\n", validation.Failures)AuthValidation Struct
Section titled “AuthValidation Struct”type AuthValidation struct { Passed bool // True if SPF, DKIM, and DMARC all passed SPFPassed bool // SPF passed DKIMPassed bool // At least one DKIM passed DMARCPassed bool // DMARC passed ReverseDNSPassed bool // Reverse DNS passed Failures []string // Slice of failure descriptions}Validation Examples
Section titled “Validation Examples”All checks pass:
validation := email.AuthResults.Validate()
// AuthValidation{// Passed: true,// SPFPassed: true,// DKIMPassed: true,// DMARCPassed: true,// ReverseDNSPassed: true,// Failures: [],// }
if !validation.Passed { t.Error("expected all authentication checks to pass")}Some checks fail:
validation := email.AuthResults.Validate()
// AuthValidation{// Passed: false,// SPFPassed: false,// DKIMPassed: true,// DMARCPassed: false,// ReverseDNSPassed: true,// Failures: []string{// "SPF check failed: fail (domain: example.com)",// "DMARC policy: fail (policy: reject)",// },// }
if !validation.Passed { fmt.Println("Authentication failures:") for _, failure := range validation.Failures { fmt.Printf(" - %s\n", failure) }}IsPassing Method
Section titled “IsPassing Method”Quick check if all primary authentication checks passed:
if email.AuthResults.IsPassing() { fmt.Println("All authentication checks passed")} else { fmt.Println("Some authentication checks failed")}Note: IsPassing() is equivalent to Validate().Passed and checks SPF, DKIM, and DMARC. Reverse DNS is not included in this check.
Package-Level Validation Functions
Section titled “Package-Level Validation Functions”The authresults package also provides functions that return errors for validation:
import "github.com/vaultsandbox/client-go/authresults"
// Validate all checksif err := authresults.Validate(email.AuthResults); err != nil { log.Printf("validation failed: %v", err)}
// Validate individual checksif err := authresults.ValidateSPF(email.AuthResults); err != nil { log.Printf("SPF failed: %v", err)}
if err := authresults.ValidateDKIM(email.AuthResults); err != nil { log.Printf("DKIM failed: %v", err)}
if err := authresults.ValidateDMARC(email.AuthResults); err != nil { log.Printf("DMARC failed: %v", err)}
if err := authresults.ValidateReverseDNS(email.AuthResults); err != nil { log.Printf("Reverse DNS failed: %v", err)}Sentinel Errors
Section titled “Sentinel Errors”var ( ErrSPFFailed = errors.New("SPF check failed") ErrDKIMFailed = errors.New("DKIM check failed") ErrDMARCFailed = errors.New("DMARC check failed") ErrReverseDNSFailed = errors.New("reverse DNS check failed") ErrNoAuthResults = errors.New("no authentication results available"))Use errors.Is to check for specific failures with individual validation functions:
if err := authresults.ValidateSPF(email.AuthResults); err != nil { if errors.Is(err, authresults.ErrSPFFailed) { fmt.Println("SPF check failed - check your SPF record") } else if errors.Is(err, authresults.ErrNoAuthResults) { fmt.Println("No SPF results available") }}ValidationError Type
Section titled “ValidationError Type”The package-level Validate() function returns a *ValidationError when validation fails, which contains all individual error messages:
type ValidationError struct { Errors []string}
func (e *ValidationError) Error() string // Returns errors joined with "; "This allows you to access individual failure messages:
if err := authresults.Validate(email.AuthResults); err != nil { // Type assert to access individual errors if ve, ok := err.(*authresults.ValidationError); ok { for _, msg := range ve.Errors { fmt.Printf("- %s\n", msg) } }}Note: The package-level Validate() function returns *ValidationError or ErrNoAuthResults, while the individual functions (ValidateSPF, ValidateDKIM, etc.) return their respective sentinel errors.
Testing Patterns
Section titled “Testing Patterns”Strict Authentication
Section titled “Strict Authentication”func TestEmailPassesAllAuthenticationChecks(t *testing.T) { sendEmail(inbox.EmailAddress())
email, err := inbox.WaitForEmail(ctx, vaultsandbox.WithWaitTimeout(10*time.Second)) if err != nil { t.Fatal(err) }
validation := email.AuthResults.Validate()
if !validation.Passed { t.Errorf("expected all checks to pass, failures: %v", validation.Failures) } if !validation.SPFPassed { t.Error("expected SPF to pass") } if !validation.DKIMPassed { t.Error("expected DKIM to pass") } if !validation.DMARCPassed { t.Error("expected DMARC to pass") }}Lenient Authentication
Section titled “Lenient Authentication”func TestEmailHasValidDKIMSignature(t *testing.T) { sendEmail(inbox.EmailAddress())
email, err := inbox.WaitForEmail(ctx, vaultsandbox.WithWaitTimeout(10*time.Second)) if err != nil { t.Fatal(err) }
// Only check DKIM (most reliable) if len(email.AuthResults.DKIM) == 0 { t.Fatal("expected DKIM results") } if email.AuthResults.DKIM[0].Result != "pass" { t.Errorf("expected DKIM pass, got %s", email.AuthResults.DKIM[0].Result) }}Handling Missing Authentication
Section titled “Handling Missing Authentication”func TestHandlesEmailsWithoutAuthentication(t *testing.T) { email, err := inbox.WaitForEmail(ctx, vaultsandbox.WithWaitTimeout(10*time.Second)) if err != nil { t.Fatal(err) }
// Some senders don't have SPF/DKIM configured validation := email.AuthResults.Validate()
// Log results for debugging if !validation.Passed { t.Logf("Auth failures (expected for test emails): %v", validation.Failures) }}Testing Specific Checks
Section titled “Testing Specific Checks”func TestEmailAuthentication(t *testing.T) { ctx := context.Background() inbox, err := client.CreateInbox(ctx) if err != nil { t.Fatal(err) } defer inbox.Delete(ctx)
sendEmail(inbox.EmailAddress())
email, err := inbox.WaitForEmail(ctx, vaultsandbox.WithWaitTimeout(10*time.Second)) if err != nil { t.Fatal(err) }
t.Run("SPF check", func(t *testing.T) { if email.AuthResults.SPF != nil { result := email.AuthResults.SPF.Result if result != "pass" && result != "neutral" && result != "softfail" { t.Errorf("unexpected SPF result: %s", result) } } })
t.Run("DKIM check", func(t *testing.T) { if len(email.AuthResults.DKIM) > 0 { anyPassed := false for _, d := range email.AuthResults.DKIM { if d.Result == "pass" { anyPassed = true break } } if !anyPassed { t.Error("expected at least one DKIM signature to pass") } } })
t.Run("DMARC check", func(t *testing.T) { if email.AuthResults.DMARC != nil { result := email.AuthResults.DMARC.Result if result != "pass" && result != "none" { t.Errorf("unexpected DMARC result: %s", result) } } })}Why Authentication Matters
Section titled “Why Authentication Matters”Production Readiness
Section titled “Production Readiness”Testing authentication catches issues like:
- Misconfigured SPF records - emails rejected by Gmail/Outlook
- Missing DKIM signatures - reduced deliverability
- DMARC failures - emails sent to spam
- Reverse DNS mismatches - flagged as suspicious
Real-World Example
Section titled “Real-World Example”func TestProductionEmailConfiguration(t *testing.T) { app.SendWelcomeEmail(inbox.EmailAddress())
email, err := inbox.WaitForEmail(ctx, vaultsandbox.WithWaitTimeout(10*time.Second)) if err != nil { t.Fatal(err) }
validation := email.AuthResults.Validate()
// In production, these should all pass if !validation.Passed { t.Log("Email authentication issues detected:") for _, f := range validation.Failures { t.Logf(" %s", f) } t.Log("") t.Log("Action required:")
if !validation.SPFPassed { t.Log("- Fix SPF record for your domain") } if !validation.DKIMPassed { t.Log("- Configure DKIM signing in your email service") } if !validation.DMARCPassed { t.Log("- Add/fix DMARC policy") }
t.Fail() }}Troubleshooting
Section titled “Troubleshooting”No Authentication Results
Section titled “No Authentication Results”if email.AuthResults.SPF == nil && len(email.AuthResults.DKIM) == 0 && email.AuthResults.DMARC == nil { fmt.Println("No authentication performed") fmt.Println("This may happen for:") fmt.Println("- Emails sent from localhost/internal servers") fmt.Println("- Test SMTP servers without authentication")}All Checks Fail
Section titled “All Checks Fail”validation := email.AuthResults.Validate()
if !validation.Passed { fmt.Printf("Authentication failed: %v\n", validation.Failures)
// Common causes: // 1. No SPF record: Add "v=spf1 ip4:YOUR_IP -all" to DNS // 2. No DKIM: Configure your mail server to sign emails // 3. No DMARC: Add "v=DMARC1; p=none" to DNS // 4. Wrong IP: Update SPF record with correct server IP}Understanding Failure Reasons
Section titled “Understanding Failure Reasons”validation := email.AuthResults.Validate()
for _, failure := range validation.Failures { switch { case strings.Contains(failure, "SPF"): fmt.Println("Fix SPF: Update DNS TXT record for your domain") case strings.Contains(failure, "DKIM"): fmt.Println("Fix DKIM: Enable DKIM signing in your email service") case strings.Contains(failure, "DMARC"): fmt.Println("Fix DMARC: Add DMARC policy to DNS") }}Next Steps
Section titled “Next Steps”- Email Authentication Guide - Testing authentication in depth
- Email API Reference - Understanding email structure
- Testing Patterns - Real-world testing examples
- Gateway Security - Understanding the security model