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 Object
Section titled “AuthResults Object”Every email has an authResults property:
const email = await inbox.waitForEmail({ timeout: 10000 });
const auth = email.authResults;
console.log(auth.spf); // SPF resultconsole.log(auth.dkim); // DKIM results (array)console.log(auth.dmarc); // DMARC resultconsole.log(auth.reverseDns); // Reverse DNS resultSPF (Sender Policy Framework)
Section titled “SPF (Sender Policy Framework)”Verifies the sending server is authorized to send from the sender’s domain.
SPF Result Structure
Section titled “SPF Result Structure”const spf = email.authResults.spf;
if (spf) { console.log(spf.result); // "pass", "fail", "softfail", "neutral", etc. console.log(spf.domain); // Domain checked console.log(spf.details); // Human-readable details}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 |
skipped | Check was disabled (see note below) |
SPF Example
Section titled “SPF Example”const email = await inbox.waitForEmail({ timeout: 10000 });
if (email.authResults.spf) { const spf = email.authResults.spf;
expect(spf.result).toBe('pass'); expect(spf.domain).toBe('example.com');
console.log(`SPF ${spf.result} for ${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.
DKIM Result Structure
Section titled “DKIM Result Structure”const dkim = email.authResults.dkim; // Array of results
if (dkim && dkim.length > 0) { dkim.forEach((result) => { console.log(result.result); // "pass", "fail", "none" console.log(result.domain); // Signing domain console.log(result.selector); // DKIM selector console.log(result.signature); // DKIM signature details });}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 |
skipped | Check was disabled (see note below) |
DKIM Example
Section titled “DKIM Example”const email = await inbox.waitForEmail({ timeout: 10000 });
if (email.authResults.dkim && email.authResults.dkim.length > 0) { const dkim = email.authResults.dkim[0];
expect(dkim.result).toBe('pass'); expect(dkim.domain).toBe('example.com');
console.log(`DKIM ${dkim.result} (${dkim.selector}._domainkey.${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.
DMARC Result Structure
Section titled “DMARC Result Structure”const dmarc = email.authResults.dmarc;
if (dmarc) { console.log(dmarc.result); // "pass", "fail", "none" console.log(dmarc.domain); // Domain checked console.log(dmarc.policy); // Domain's policy (none, quarantine, reject) console.log(dmarc.aligned); // Whether SPF/DKIM aligns with From domain}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 |
skipped | Check was disabled (see note below) |
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”const email = await inbox.waitForEmail({ timeout: 10000 });
if (email.authResults.dmarc) { const dmarc = email.authResults.dmarc;
expect(dmarc.result).toBe('pass'); expect(dmarc.domain).toBe('example.com');
console.log(`DMARC ${dmarc.result} (policy: ${dmarc.policy})`);}Reverse DNS
Section titled “Reverse DNS”Verifies the sending server’s IP resolves to a hostname that matches the sending domain.
Reverse DNS Result Structure
Section titled “Reverse DNS Result Structure”const reverseDns = email.authResults.reverseDns;
if (reverseDns) { console.log(reverseDns.result); // "pass", "fail", "none", or "skipped" console.log(reverseDns.ip); // Server IP console.log(reverseDns.hostname); // Resolved hostname (may be empty)}Reverse DNS Status Values
Section titled “Reverse DNS Status Values”| Status | Meaning |
|---|---|
pass | Reverse DNS verified |
fail | Reverse DNS check failed |
none | No reverse DNS record found |
skipped | Check was disabled (see note below) |
Breaking Change (v0.7.0): The verified boolean property has been replaced with a result string. Migrate existing code by replacing verified === true with result === 'pass'.
Reverse DNS Example
Section titled “Reverse DNS Example”const email = await inbox.waitForEmail({ timeout: 10000 });
if (email.authResults.reverseDns) { const rdns = email.authResults.reverseDns;
console.log(`Reverse DNS: ${rdns.ip} → ${rdns.hostname}`); console.log(`Result: ${rdns.result}`);
// Check if reverse DNS passed if (rdns.result === 'pass') { console.log('Reverse DNS verified'); }}When skipped Status Appears
Section titled “When skipped Status Appears”The skipped status appears for any authentication check when:
- The inbox was created with
emailAuth: false - The server has globally disabled that specific check
- The master switch
VSB_EMAIL_AUTH_ENABLED=falseis set on the server
The skipped status is informational and indicates the check was intentionally disabled, not that it failed.
Validation Helper
Section titled “Validation Helper”The validate() method provides a summary of all authentication checks. The skipped status is treated as passing (not a failure), since it indicates the check was intentionally disabled.
const validation = email.authResults.validate();
console.log(validation.passed); // Overall pass/failconsole.log(validation.spfPassed); // SPF check (true if pass or skipped)console.log(validation.dkimPassed); // DKIM check (true if pass or skipped)console.log(validation.dmarcPassed); // DMARC check (true if pass or skipped)console.log(validation.reverseDnsPassed); // Reverse DNS check (true if pass or skipped)console.log(validation.failures); // Array of failure reasonsValidation Result Structure
Section titled “Validation Result Structure”interface AuthValidation { passed: boolean; // True if all checks passed spfPassed: boolean; // SPF passed dkimPassed: boolean; // At least one DKIM passed dmarcPassed: boolean; // DMARC passed reverseDnsPassed: boolean; // Reverse DNS passed failures: string[]; // Array of failure descriptions}Validation Examples
Section titled “Validation Examples”All checks pass:
const validation = email.authResults.validate();
// {// passed: true,// spfPassed: true,// dkimPassed: true,// dmarcPassed: true,// reverseDnsPassed: true,// failures: []// }
expect(validation.passed).toBe(true);Some checks fail:
const validation = email.authResults.validate();
// {// passed: false,// spfPassed: false,// dkimPassed: true,// dmarcPassed: false,// reverseDnsPassed: true,// failures: [// "SPF check failed: status 'fail'",// "DMARC check failed: status 'fail'"// ]// }
if (!validation.passed) { console.error('Authentication failures:'); validation.failures.forEach((failure) => { console.error(` - ${failure}`); });}Handling skipped checks:
// Create inbox with auth disabledconst inbox = await client.createInbox({ emailAuth: false });const email = await inbox.waitForEmail({ timeout: 10000 });
// Check if SPF was skippedif (email.authResults.spf?.result === 'skipped') { console.log('SPF check was disabled for this inbox');}
// The validate() method treats "skipped" as passingconst validation = email.authResults.validate();
// {// passed: true,// spfPassed: true, // true because skipped// dkimPassed: true, // true because skipped// dmarcPassed: true, // true because skipped// reverseDnsPassed: true, // true because skipped// failures: []// }Testing Patterns
Section titled “Testing Patterns”Strict Authentication
Section titled “Strict Authentication”test('email passes all authentication checks', async () => { await sendEmail(inbox.emailAddress);
const email = await inbox.waitForEmail({ timeout: 10000 }); const validation = email.authResults.validate();
expect(validation.passed).toBe(true); expect(validation.spfPassed).toBe(true); expect(validation.dkimPassed).toBe(true); expect(validation.dmarcPassed).toBe(true);});Lenient Authentication
Section titled “Lenient Authentication”test('email has valid DKIM signature', async () => { await sendEmail(inbox.emailAddress);
const email = await inbox.waitForEmail({ timeout: 10000 });
// Only check DKIM (most reliable) expect(email.authResults.dkim).toBeDefined(); expect(email.authResults.dkim.length).toBeGreaterThan(0); expect(email.authResults.dkim[0].result).toBe('pass');});Handling Missing Authentication
Section titled “Handling Missing Authentication”test('handles emails without authentication', async () => { const email = await inbox.waitForEmail({ timeout: 10000 });
// Some senders don't have SPF/DKIM configured const validation = email.authResults.validate();
// Check if validation was performed expect(typeof validation.passed).toBe('boolean'); expect(Array.isArray(validation.failures)).toBe(true);
// Log results for debugging if (!validation.passed) { console.log('Auth failures (expected for test emails):', validation.failures); }});Testing Specific Checks
Section titled “Testing Specific Checks”describe('Email Authentication', () => { let inbox, email;
beforeEach(async () => { inbox = await client.createInbox(); await sendEmail(inbox.emailAddress); email = await inbox.waitForEmail({ timeout: 10000 }); });
afterEach(async () => { await inbox.delete(); });
test('SPF check', () => { if (email.authResults.spf) { expect(email.authResults.spf.result).toMatch(/pass|neutral|softfail/); } });
test('DKIM check', () => { if (email.authResults.dkim && email.authResults.dkim.length > 0) { const anyPassed = email.authResults.dkim.some((d) => d.result === 'pass'); expect(anyPassed).toBe(true); } });
test('DMARC check', () => { if (email.authResults.dmarc) { expect(email.authResults.dmarc.result).toMatch(/pass|none/); } });});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”test('production email configuration', async () => { await app.sendWelcomeEmail(inbox.emailAddress);
const email = await inbox.waitForEmail({ timeout: 10000 }); const validation = email.authResults.validate();
// In production, these should all pass if (!validation.passed) { console.error('❌ Email authentication issues detected:'); validation.failures.forEach((f) => console.error(` ${f}`)); console.error(''); console.error('Action required:');
if (!validation.spfPassed) { console.error('- Fix SPF record for your domain'); } if (!validation.dkimPassed) { console.error('- Configure DKIM signing in your email service'); } if (!validation.dmarcPassed) { console.error('- Add/fix DMARC policy'); } }
// Fail test if authentication fails expect(validation.passed).toBe(true);});Troubleshooting
Section titled “Troubleshooting”No Authentication Results
Section titled “No Authentication Results”if (!email.authResults.spf && !email.authResults.dkim && !email.authResults.dmarc) { console.log('No authentication performed'); console.log('This may happen for:'); console.log('- Emails sent from localhost/internal servers'); console.log('- Test SMTP servers without authentication');}All Checks Fail
Section titled “All Checks Fail”const validation = email.authResults.validate();
if (!validation.passed) { console.error('Authentication failed:', 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”const validation = email.authResults.validate();
validation.failures.forEach((failure) => { if (failure.includes('SPF')) { console.log('Fix SPF: Update DNS TXT record for your domain'); } if (failure.includes('DKIM')) { console.log('Fix DKIM: Enable DKIM signing in your email service'); } if (failure.includes('DMARC')) { console.log('Fix DMARC: Add DMARC policy to DNS'); }});Next Steps
Section titled “Next Steps”- Email Authentication Guide - Testing authentication in depth
- Email Objects - Understanding email structure
- Testing Patterns - Real-world testing examples
- Gateway Security - Understanding the security model