Email Authentication Testing
VaultSandbox validates SPF, DKIM, DMARC, and reverse DNS for every email, helping you catch authentication issues before production.
Why Test Email Authentication?
Section titled “Why Test Email Authentication?”Email authentication prevents:
- Emails being marked as spam
- Emails being rejected by receivers
- Domain spoofing and phishing
- Delivery failures
Testing authentication ensures your emails will be trusted by Gmail, Outlook, and other providers.
Basic Authentication Check
Section titled “Basic Authentication Check”Using validate()
Section titled “Using validate()”const email = await inbox.waitForEmail({ timeout: 10000 });const validation = email.authResults.validate();
if (validation.passed) { console.log('✅ All authentication checks passed');} else { console.error('❌ Authentication failures:'); validation.failures.forEach((f) => console.error(` - ${f}`));}Checking Individual Results
Section titled “Checking Individual Results”const auth = email.authResults;
console.log('SPF:', auth.spf?.result);console.log('DKIM:', auth.dkim?.[0]?.result);console.log('DMARC:', auth.dmarc?.result);console.log('Reverse DNS:', auth.reverseDns?.verified);Testing SPF
Section titled “Testing SPF”Basic SPF Test
Section titled “Basic SPF Test”test('email passes SPF check', async () => { await sendEmail(inbox.emailAddress);
const email = await inbox.waitForEmail({ timeout: 10000 });
expect(email.authResults.spf).toBeDefined(); expect(email.authResults.spf.result).toBe('pass');});Detailed SPF Validation
Section titled “Detailed SPF Validation”test('SPF validation details', async () => { const email = await inbox.waitForEmail({ timeout: 10000 }); const spf = email.authResults.spf;
if (spf) { expect(spf.result).toBe('pass'); expect(spf.domain).toBe('example.com');
console.log(`SPF ${spf.result} for ${spf.domain}`); console.log(`Details: ${spf.details}`); }});Handling SPF Failures
Section titled “Handling SPF Failures”test('handles SPF failure', async () => { const email = await inbox.waitForEmail({ timeout: 10000 }); const spf = email.authResults.spf;
if (spf && spf.result !== 'pass') { console.warn(`SPF ${spf.result}:`, spf.details);
// Common failures if (spf.result === 'fail') { console.error('Server IP not authorized in SPF record'); console.error('Action: Add server IP to SPF record'); } else if (spf.result === 'softfail') { console.warn('Server probably not authorized (~all in SPF)'); } else if (spf.result === 'none') { console.error('No SPF record found'); console.error('Action: Add SPF record to DNS'); } }});Testing DKIM
Section titled “Testing DKIM”Basic DKIM Test
Section titled “Basic DKIM Test”test('email has valid DKIM signature', async () => { await sendEmail(inbox.emailAddress);
const email = await inbox.waitForEmail({ timeout: 10000 });
expect(email.authResults.dkim).toBeDefined(); expect(email.authResults.dkim.length).toBeGreaterThan(0); expect(email.authResults.dkim[0].result).toBe('pass');});Multiple DKIM Signatures
Section titled “Multiple DKIM Signatures”test('validates all DKIM signatures', async () => { const email = await inbox.waitForEmail({ timeout: 10000 }); const dkim = email.authResults.dkim;
if (dkim && dkim.length > 0) { console.log(`Email has ${dkim.length} DKIM signature(s)`);
dkim.forEach((sig, index) => { console.log(`Signature ${index + 1}:`, { result: sig.result, domain: sig.domain, selector: sig.selector, });
expect(sig.result).toBe('pass'); });
// At least one signature should pass const anyPassed = dkim.some((sig) => sig.result === 'pass'); expect(anyPassed).toBe(true); }});DKIM Selector Verification
Section titled “DKIM Selector Verification”test('DKIM uses correct selector', async () => { const email = await inbox.waitForEmail({ timeout: 10000 }); const dkim = email.authResults.dkim?.[0];
if (dkim) { expect(dkim.selector).toBe('default'); // Or your expected selector expect(dkim.domain).toBe('example.com');
// DKIM DNS record should exist at: // {selector}._domainkey.{domain} console.log(`DKIM key at: ${dkim.selector}._domainkey.${dkim.domain}`); }});Testing DMARC
Section titled “Testing DMARC”Basic DMARC Test
Section titled “Basic DMARC Test”test('email passes DMARC', async () => { await sendEmail(inbox.emailAddress);
const email = await inbox.waitForEmail({ timeout: 10000 });
expect(email.authResults.dmarc).toBeDefined(); expect(email.authResults.dmarc.result).toBe('pass');});DMARC Policy Verification
Section titled “DMARC Policy Verification”test('DMARC policy is enforced', async () => { const email = await inbox.waitForEmail({ timeout: 10000 }); const dmarc = email.authResults.dmarc;
if (dmarc) { console.log('DMARC result:', dmarc.result); console.log('DMARC policy:', dmarc.policy);
// Policy should be restrictive in production expect(['quarantine', 'reject']).toContain(dmarc.policy); }});DMARC Alignment Check
Section titled “DMARC Alignment Check”test('DMARC alignment requirements', async () => { const email = await inbox.waitForEmail({ timeout: 10000 });
// DMARC requires either SPF or DKIM to align with From domain const validation = email.authResults.validate();
if (!validation.dmarcPassed) { console.log('DMARC failed. Checking alignment:'); console.log('SPF passed:', validation.spfPassed); console.log('DKIM passed:', validation.dkimPassed);
// At least one should pass for DMARC to pass expect(validation.spfPassed || validation.dkimPassed).toBe(true); }});Testing Reverse DNS
Section titled “Testing Reverse DNS”Basic Reverse DNS Test
Section titled “Basic Reverse DNS Test”test('server has valid reverse DNS', async () => { const email = await inbox.waitForEmail({ timeout: 10000 }); const rdns = email.authResults.reverseDns;
if (rdns) { expect(rdns.verified).toBe(true); expect(rdns.hostname).toBeTruthy();
console.log(`Reverse DNS: ${rdns.ip} → ${rdns.hostname}`); console.log(`Verified: ${rdns.verified}`); }});Complete Authentication Test
Section titled “Complete Authentication Test”All Checks Pass
Section titled “All Checks Pass”test('email passes all authentication checks', async () => { await app.sendProductionEmail(inbox.emailAddress);
const email = await inbox.waitForEmail({ timeout: 10000 }); const validation = email.authResults.validate();
// All checks should pass in production expect(validation.passed).toBe(true); expect(validation.spfPassed).toBe(true); expect(validation.dkimPassed).toBe(true); expect(validation.dmarcPassed).toBe(true);
// Log results console.log('Authentication Results:'); console.log(' SPF:', validation.spfPassed ? '✅' : '❌'); console.log(' DKIM:', validation.dkimPassed ? '✅' : '❌'); console.log(' DMARC:', validation.dmarcPassed ? '✅' : '❌'); console.log(' Reverse DNS:', validation.reverseDnsPassed ? '✅' : '❌');});Graceful Failure Handling
Section titled “Graceful Failure Handling”test('handles authentication failures gracefully', async () => { const email = await inbox.waitForEmail({ timeout: 10000 }); const validation = email.authResults.validate();
// Log failures without failing test (for non-production) if (!validation.passed) { console.warn('⚠️ Authentication issues detected:'); validation.failures.forEach((failure) => { console.warn(` - ${failure}`); });
// Provide remediation steps if (!validation.spfPassed) { console.log('\nTo fix SPF:'); console.log(' Add to DNS: v=spf1 ip4:YOUR_SERVER_IP -all'); }
if (!validation.dkimPassed) { console.log('\nTo fix DKIM:'); console.log(' 1. Generate DKIM keys'); console.log(' 2. Add public key to DNS'); console.log(' 3. Configure mail server to sign emails'); }
if (!validation.dmarcPassed) { console.log('\nTo fix DMARC:'); } }
// In production, this should be expect(validation.passed).toBe(true)});Real-World Testing Patterns
Section titled “Real-World Testing Patterns”Pre-Production Validation
Section titled “Pre-Production Validation”describe('Email Authentication - Pre-Production', () => { test('validates staging environment email auth', async () => { const email = await inbox.waitForEmail({ timeout: 10000 }); const auth = email.authResults;
// SPF should be configured if (auth.spf) { if (auth.spf.result !== 'pass') { console.error('❌ SPF not configured correctly'); console.error(` Result: ${auth.spf.result}`); console.error(` Details: ${auth.spf.details}`); } expect(auth.spf.result).toMatch(/pass|neutral/); }
// DKIM should be present if (auth.dkim && auth.dkim.length > 0) { const anyValid = auth.dkim.some((d) => d.result === 'pass'); if (!anyValid) { console.error('❌ No valid DKIM signatures'); console.error(' Fix: Configure DKIM signing in mail server'); } expect(anyValid).toBe(true); } });});Production Readiness Check
Section titled “Production Readiness Check”test('production email configuration', async () => { const email = await inbox.waitForEmail({ timeout: 10000 }); const validation = email.authResults.validate();
// Production requirements const productionReady = { spf: validation.spfPassed, dkim: validation.dkimPassed, dmarc: validation.dmarcPassed, allPassed: validation.passed, };
console.log('Production Readiness:'); console.table(productionReady);
// Fail if not production-ready if (!validation.passed) { const issues = validation.failures.join('\n '); throw new Error( `Email not production-ready:\n ${issues}\n\n` + `Fix these issues before deploying to production.` ); }
expect(validation.passed).toBe(true);});Debugging Authentication Issues
Section titled “Debugging Authentication Issues”Verbose Logging
Section titled “Verbose Logging”function logAuthenticationDetails(email) { const auth = email.authResults;
console.log('\n=== Email Authentication Details ===\n');
// SPF if (auth.spf) { console.log('SPF:'); console.log(` Result: ${auth.spf.result}`); console.log(` Domain: ${auth.spf.domain}`); console.log(` Details: ${auth.spf.details}`); } else { console.log('SPF: No result'); }
// DKIM if (auth.dkim && auth.dkim.length > 0) { console.log('\nDKIM:'); auth.dkim.forEach((sig, i) => { console.log(` Signature ${i + 1}:`); console.log(` Result: ${sig.result}`); console.log(` Domain: ${sig.domain}`); console.log(` Selector: ${sig.selector}`); console.log(` Signature: ${sig.signature}`); }); } else { console.log('\nDKIM: No signatures'); }
// DMARC if (auth.dmarc) { console.log('\nDMARC:'); console.log(` Result: ${auth.dmarc.result}`); console.log(` Domain: ${auth.dmarc.domain}`); console.log(` Policy: ${auth.dmarc.policy}`); } else { console.log('\nDMARC: No result'); }
// Reverse DNS if (auth.reverseDns) { console.log('\nReverse DNS:'); console.log(` Verified: ${auth.reverseDns.verified}`); console.log(` IP: ${auth.reverseDns.ip}`); console.log(` Hostname: ${auth.reverseDns.hostname}`); }
// Validation Summary const validation = auth.validate(); console.log('\nValidation Summary:'); console.log(` Overall: ${validation.passed ? '✅ PASS' : '❌ FAIL'}`); if (!validation.passed) { console.log(` Failures:`); validation.failures.forEach((f) => console.log(` - ${f}`)); }}
// Usageconst email = await inbox.waitForEmail({ timeout: 10000 });logAuthenticationDetails(email);Next Steps
Section titled “Next Steps”- Authentication Results - Deep dive into auth results
- Email Objects - Understanding email structure
- Testing Patterns - Real-world test examples
- Gateway Security - Understanding the security model