Skip to content

Email API

The Email class represents a decrypted email message in VaultSandbox. All emails are automatically decrypted when retrieved, so you can access content, headers, links, and attachments directly.

id: string;

Unique identifier for this email. Use this to reference the email in API calls.

const emails = await inbox.listEmails();
console.log(`Email ID: ${emails[0].id}`);
// Get specific email
const email = await inbox.getEmail(emails[0].id);

from: string;

The sender’s email address.

const email = await inbox.waitForEmail({ timeout: 10000 });
console.log(`From: ${email.from}`);
expect(email.from).toBe('noreply@example.com');

to: string[]

Array of recipient email addresses.

const email = await inbox.waitForEmail({ timeout: 10000 });
console.log(`To: ${email.to.join(', ')}`);
// Check if specific recipient is included
expect(email.to).toContain(inbox.emailAddress);

subject: string;

The email subject line.

const email = await inbox.waitForEmail({
timeout: 10000,
subject: /Welcome/,
});
console.log(`Subject: ${email.subject}`);
expect(email.subject).toContain('Welcome');

text: string | null;

Plain text content of the email. May be null if the email only has HTML content.

const email = await inbox.waitForEmail({ timeout: 10000 });
if (email.text) {
console.log('Plain text version:');
console.log(email.text);
// Validate content
expect(email.text).toContain('Thank you for signing up');
}

html: string | null;

HTML content of the email. May be null if the email only has plain text.

const email = await inbox.waitForEmail({ timeout: 10000 });
if (email.html) {
console.log('HTML version present');
// Validate HTML structure
expect(email.html).toContain('<a href=');
expect(email.html).toContain('</html>');
// Check for specific elements
expect(email.html).toMatch(/<img[^>]+src="/);
}

receivedAt: Date;

The date and time when the email was received by VaultSandbox.

const email = await inbox.waitForEmail({ timeout: 10000 });
console.log(`Received at: ${email.receivedAt.toISOString()}`);
// Check if email was received recently
const now = Date.now();
const received = email.receivedAt.getTime();
const ageInSeconds = (now - received) / 1000;
expect(ageInSeconds).toBeLessThan(60); // Within last minute

isRead: boolean;

Whether this email has been marked as read.

const email = await inbox.waitForEmail({ timeout: 10000 });
console.log(`Read status: ${email.isRead}`);
// Mark as read
await email.markAsRead();
// Verify status changed
const updated = await inbox.getEmail(email.id);
expect(updated.isRead).toBe(true);

links: string[]

All URLs automatically extracted from the email content (both text and HTML).

const email = await inbox.waitForEmail({
timeout: 10000,
subject: /Password Reset/,
});
console.log(`Found ${email.links.length} links:`);
email.links.forEach((url) => console.log(` - ${url}`));
// Find specific link
const resetLink = email.links.find((url) => url.includes('/reset-password'));
expect(resetLink).toBeDefined();
expect(resetLink).toMatch(/^https:\/\//);
// Extract query parameters
const url = new URL(resetLink);
const token = url.searchParams.get('token');
expect(token).toBeTruthy();

headers: Record<string, unknown>;

All email headers as a key-value object.

const email = await inbox.waitForEmail({ timeout: 10000 });
console.log('Headers:');
console.log(` Content-Type: ${email.headers['content-type']}`);
console.log(` Message-ID: ${email.headers['message-id']}`);
// Check for custom headers
if (email.headers['x-custom-header']) {
console.log(`Custom header: ${email.headers['x-custom-header']}`);
}

attachments: AttachmentData[]

Array of email attachments, automatically decrypted and ready to use.

interface AttachmentData {
filename: string;
contentType: string;
size: number;
contentId?: string;
contentDisposition?: string;
checksum?: string;
content?: Uint8Array;
}
const email = await inbox.waitForEmail({
timeout: 10000,
subject: /Invoice/,
});
console.log(`Attachments: ${email.attachments.length}`);
email.attachments.forEach((attachment) => {
console.log(` - ${attachment.filename} (${attachment.size} bytes)`);
console.log(` Type: ${attachment.contentType}`);
});
// Find PDF attachment
const pdf = email.attachments.find((att) => att.contentType === 'application/pdf');
if (pdf && pdf.content) {
fs.writeFileSync(`./downloads/${pdf.filename}`, pdf.content);
console.log(`Saved ${pdf.filename}`);
}
// Process text attachment
const textFile = email.attachments.find((att) => att.contentType.includes('text'));
if (textFile && textFile.content) {
const text = new TextDecoder().decode(textFile.content);
console.log('Text content:', text);
}
// Parse JSON attachment
const jsonFile = email.attachments.find((att) => att.contentType.includes('json'));
if (jsonFile && jsonFile.content) {
const json = new TextDecoder().decode(jsonFile.content);
const data = JSON.parse(json);
console.log('JSON data:', data);
}

See the Attachments Guide for more examples.


authResults: AuthResults;

Email authentication results including SPF, DKIM, and DMARC validation.

interface AuthResults {
spf?: SPFResult;
dkim?: DKIMResult[];
dmarc?: DMARCResult;
reverseDns?: ReverseDNSResult;
validate(): AuthValidation;
}
const email = await inbox.waitForEmail({ timeout: 10000 });
// Validate all authentication
const validation = email.authResults.validate();
console.log(`Authentication passed: ${validation.passed}`);
if (!validation.passed) {
console.log('Failures:');
validation.failures.forEach((failure) => console.log(` - ${failure}`));
}
// Check individual results
if (email.authResults.spf) {
console.log(`SPF Result: ${email.authResults.spf.result}`);
}
if (email.authResults.dkim && email.authResults.dkim.length > 0) {
console.log(`DKIM Result: ${email.authResults.dkim[0].result}`);
}
if (email.authResults.dmarc) {
console.log(`DMARC Result: ${email.authResults.dmarc.result}`);
}

See the Authentication Guide for more details.


metadata: Record<string, unknown>;

Additional metadata associated with the email.

const email = await inbox.waitForEmail({ timeout: 10000 });
if (email.metadata) {
console.log('Metadata:', email.metadata);
}

spamAnalysis?: SpamAnalysisResult;

Spam analysis results for the email. This property is only present when spam analysis is enabled on the server and for the inbox.

interface SpamAnalysisResult {
status: 'analyzed' | 'skipped' | 'error';
score?: number;
requiredScore?: number;
action?: SpamAction;
isSpam?: boolean;
symbols?: SpamSymbol[];
processingTimeMs?: number;
info?: string;
}
type SpamAction = 'no action' | 'greylist' | 'add header' | 'rewrite subject' | 'soft reject' | 'reject';
interface SpamSymbol {
name: string;
score: number;
description?: string;
options?: string[];
}
const email = await inbox.waitForEmail({ timeout: 10000 });
if (email.spamAnalysis) {
console.log(`Status: ${email.spamAnalysis.status}`);
if (email.spamAnalysis.status === 'analyzed') {
console.log(`Spam score: ${email.spamAnalysis.score}`);
console.log(`Required score: ${email.spamAnalysis.requiredScore}`);
console.log(`Is spam: ${email.spamAnalysis.isSpam}`);
console.log(`Action: ${email.spamAnalysis.action}`);
// View triggered rules
if (email.spamAnalysis.symbols) {
console.log('Triggered rules:');
email.spamAnalysis.symbols.forEach((symbol) => {
console.log(` ${symbol.name}: ${symbol.score} - ${symbol.description || ''}`);
});
}
}
}

See the Spam Analysis Guide for more details.

Marks this email as read.

markAsRead(): Promise<void>
const email = await inbox.waitForEmail({ timeout: 10000 });
console.log(`Read status: ${email.isRead}`); // false
await email.markAsRead();
console.log('Marked as read');
// Verify status changed
const updated = await inbox.getEmail(email.id);
expect(updated.isRead).toBe(true);

Deletes this email from the inbox.

delete(): Promise<void>
const email = await inbox.waitForEmail({ timeout: 10000 });
// Delete the email
await email.delete();
console.log('Email deleted');
// Verify deletion
const emails = await inbox.listEmails();
expect(emails.find((e) => e.id === email.id)).toBeUndefined();

Gets the raw MIME source of this email (decrypted).

getRaw(): Promise<RawEmail>

Promise<RawEmail> - Raw email source

interface RawEmail {
id: string;
raw: string;
}
const email = await inbox.waitForEmail({ timeout: 10000 });
const raw = await email.getRaw();
console.log('Raw MIME source:');
console.log(raw.raw);
// Save to .eml file
fs.writeFileSync(`email-${email.id}.eml`, raw.raw);

Returns whether the email is classified as spam based on spam analysis.

isSpam(): boolean | null
  • true - Email is classified as spam
  • false - Email is not spam
  • null - Spam analysis not available (status !== ‘analyzed’)
const email = await inbox.waitForEmail({ timeout: 10000 });
const spamStatus = email.isSpam();
if (spamStatus === true) {
console.log('This email is spam!');
} else if (spamStatus === false) {
console.log('This email is not spam');
} else {
console.log('Spam analysis not available');
}
// Use in tests
expect(email.isSpam()).toBe(false);

Returns the spam score for the email.

getSpamScore(): number | null
  • number - The spam score (positive = more spammy, negative = more legitimate)
  • null - Spam analysis not available (status !== ‘analyzed’)
const email = await inbox.waitForEmail({ timeout: 10000 });
const score = email.getSpamScore();
if (score !== null) {
console.log(`Spam score: ${score}`);
// Typical thresholds:
// < 0: Very likely legitimate
// 0-5: Probably legitimate
// 5-10: Suspicious
// > 10: Very likely spam
}
// Use in tests
const spamScore = email.getSpamScore();
expect(spamScore).not.toBeNull();
expect(spamScore).toBeLessThan(5);

The AuthResults object provides email authentication validation.

spf?: SPFResult

SPF (Sender Policy Framework) validation result.

interface SPFResult {
result: 'pass' | 'fail' | 'softfail' | 'neutral' | 'none' | 'temperror' | 'permerror' | 'skipped';
domain?: string;
ip?: string;
details?: string;
}

Note: The skipped status appears when the inbox has emailAuth: false, the server has globally disabled SPF checks, or the master switch VSB_EMAIL_AUTH_ENABLED=false is set.

dkim?: DKIMResult[]

DKIM (DomainKeys Identified Mail) validation results. May have multiple signatures.

interface DKIMResult {
result: 'pass' | 'fail' | 'none' | 'skipped';
domain?: string;
selector?: string;
signature?: string;
}

Note: The skipped status appears when the inbox has emailAuth: false, the server has globally disabled DKIM checks, or the master switch VSB_EMAIL_AUTH_ENABLED=false is set.

dmarc?: DMARCResult

DMARC (Domain-based Message Authentication) validation result.

interface DMARCResult {
result: 'pass' | 'fail' | 'none' | 'skipped';
policy?: 'none' | 'quarantine' | 'reject';
aligned?: boolean;
domain?: string;
}

Note: The skipped status appears when the inbox has emailAuth: false, the server has globally disabled DMARC checks, or the master switch VSB_EMAIL_AUTH_ENABLED=false is set.

reverseDns?: ReverseDNSResult

Reverse DNS lookup result.

interface ReverseDNSResult {
result: 'pass' | 'fail' | 'none' | 'skipped';
ip?: string;
hostname?: string;
}

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'.

Note: The skipped status appears when the inbox has emailAuth: false, the server has globally disabled reverse DNS checks, or the master switch VSB_EMAIL_AUTH_ENABLED=false is set.

Validates all authentication results and returns a summary. The skipped status is treated as passing (not a failure), since it indicates the check was intentionally disabled rather than failing.

validate(): AuthValidation
interface AuthValidation {
passed: boolean;
spfPassed: boolean;
dkimPassed: boolean;
dmarcPassed: boolean;
reverseDnsPassed: boolean;
failures: string[];
}
const email = await inbox.waitForEmail({ timeout: 10000 });
const validation = email.authResults.validate();
console.log(`Overall: ${validation.passed ? 'PASS' : 'FAIL'}`);
console.log(`SPF: ${validation.spfPassed ? 'PASS' : 'FAIL'}`);
console.log(`DKIM: ${validation.dkimPassed ? 'PASS' : 'FAIL'}`);
console.log(`DMARC: ${validation.dmarcPassed ? 'PASS' : 'FAIL'}`);
if (!validation.passed) {
console.log('\nFailures:');
validation.failures.forEach((failure) => {
console.log(` - ${failure}`);
});
}
import { VaultSandboxClient } from '@vaultsandbox/client';
import fs from 'fs';
async function completeEmailExample() {
const client = new VaultSandboxClient({
url: process.env.VAULTSANDBOX_URL,
apiKey: process.env.VAULTSANDBOX_API_KEY,
});
try {
const inbox = await client.createInbox();
console.log(`Created inbox: ${inbox.emailAddress}`);
// Trigger test email
await sendTestEmail(inbox.emailAddress);
// Wait for email
const email = await inbox.waitForEmail({
timeout: 10000,
subject: /Test/,
});
// Basic info
console.log('\n=== Email Details ===');
console.log(`ID: ${email.id}`);
console.log(`From: ${email.from}`);
console.log(`To: ${email.to.join(', ')}`);
console.log(`Subject: ${email.subject}`);
console.log(`Received: ${email.receivedAt.toISOString()}`);
console.log(`Read: ${email.isRead}`);
// Content
console.log('\n=== Content ===');
if (email.text) {
console.log('Plain text:');
console.log(email.text.substring(0, 200) + '...');
}
if (email.html) {
console.log('HTML version present');
}
// Links
console.log('\n=== Links ===');
console.log(`Found ${email.links.length} links:`);
email.links.forEach((link) => console.log(` - ${link}`));
// Attachments
console.log('\n=== Attachments ===');
console.log(`Found ${email.attachments.length} attachments:`);
email.attachments.forEach((att) => {
console.log(` - ${att.filename} (${att.contentType}, ${att.size} bytes)`);
// Save attachment
if (att.content) {
fs.writeFileSync(`./downloads/${att.filename}`, att.content);
console.log(` Saved to ./downloads/${att.filename}`);
}
});
// Authentication
console.log('\n=== Authentication ===');
const validation = email.authResults.validate();
console.log(`Overall: ${validation.passed ? 'PASS' : 'FAIL'}`);
console.log(`SPF: ${validation.spfPassed}`);
console.log(`DKIM: ${validation.dkimPassed}`);
console.log(`DMARC: ${validation.dmarcPassed}`);
if (!validation.passed) {
console.log('Failures:', validation.failures);
}
// Spam Analysis
console.log('\n=== Spam Analysis ===');
if (email.spamAnalysis) {
console.log(`Status: ${email.spamAnalysis.status}`);
if (email.spamAnalysis.status === 'analyzed') {
console.log(`Score: ${email.spamAnalysis.score}`);
console.log(`Is Spam: ${email.isSpam()}`);
console.log(`Action: ${email.spamAnalysis.action}`);
}
} else {
console.log('Spam analysis not available');
}
// Mark as read
await email.markAsRead();
console.log('\nMarked as read');
// Get raw source
const raw = await email.getRaw();
fs.writeFileSync(`email-${email.id}.eml`, raw.raw);
console.log(`Saved raw source to email-${email.id}.eml`);
// Clean up
await inbox.delete();
} finally {
await client.close();
}
}
completeEmailExample().catch(console.error);