/** * SMTP Client Helper Functions * Protocol helper functions and utilities */ import { SMTP_CODES, REGEX_PATTERNS, LINE_ENDINGS } from '../constants.js'; /** * Parse SMTP server response */ export function parseSmtpResponse(data) { const lines = data.trim().split(/\r?\n/); const firstLine = lines[0]; const match = firstLine.match(REGEX_PATTERNS.RESPONSE_CODE); if (!match) { return { code: 500, message: 'Invalid server response', raw: data }; } const code = parseInt(match[1], 10); const separator = match[2]; const message = lines.map(line => line.substring(4)).join(' '); // Check for enhanced status code const enhancedMatch = message.match(REGEX_PATTERNS.ENHANCED_STATUS); const enhancedCode = enhancedMatch ? enhancedMatch[1] : undefined; return { code, message: enhancedCode ? message.substring(enhancedCode.length + 1) : message, enhancedCode, raw: data }; } /** * Parse EHLO response and extract capabilities */ export function parseEhloResponse(response) { const lines = response.trim().split(/\r?\n/); const capabilities = { extensions: new Set(), authMethods: new Set(), pipelining: false, starttls: false, eightBitMime: false }; for (const line of lines.slice(1)) { // Skip first line (greeting) const extensionLine = line.substring(4); // Remove "250-" or "250 " const parts = extensionLine.split(/\s+/); const extension = parts[0].toUpperCase(); capabilities.extensions.add(extension); switch (extension) { case 'PIPELINING': capabilities.pipelining = true; break; case 'STARTTLS': capabilities.starttls = true; break; case '8BITMIME': capabilities.eightBitMime = true; break; case 'SIZE': if (parts[1]) { capabilities.maxSize = parseInt(parts[1], 10); } break; case 'AUTH': // Parse authentication methods for (let i = 1; i < parts.length; i++) { capabilities.authMethods.add(parts[i].toUpperCase()); } break; } } return capabilities; } /** * Format SMTP command with proper line ending */ export function formatCommand(command, ...args) { const fullCommand = args.length > 0 ? `${command} ${args.join(' ')}` : command; return fullCommand + LINE_ENDINGS.CRLF; } /** * Encode authentication string for AUTH PLAIN */ export function encodeAuthPlain(username, password) { const authString = `\0${username}\0${password}`; return Buffer.from(authString, 'utf8').toString('base64'); } /** * Encode authentication string for AUTH LOGIN */ export function encodeAuthLogin(value) { return Buffer.from(value, 'utf8').toString('base64'); } /** * Generate OAuth2 authentication string */ export function generateOAuth2String(username, accessToken) { const authString = `user=${username}\x01auth=Bearer ${accessToken}\x01\x01`; return Buffer.from(authString, 'utf8').toString('base64'); } /** * Check if response code indicates success */ export function isSuccessCode(code) { return code >= 200 && code < 300; } /** * Check if response code indicates temporary failure */ export function isTemporaryFailure(code) { return code >= 400 && code < 500; } /** * Check if response code indicates permanent failure */ export function isPermanentFailure(code) { return code >= 500; } /** * Escape email address for SMTP commands */ export function escapeEmailAddress(email) { return `<${email.trim()}>`; } /** * Extract email address from angle brackets */ export function extractEmailAddress(email) { const match = email.match(/^<(.+)>$/); return match ? match[1] : email.trim(); } /** * Generate unique connection ID */ export function generateConnectionId() { return `smtp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; } /** * Format timeout duration for human readability */ export function formatTimeout(milliseconds) { if (milliseconds < 1000) { return `${milliseconds}ms`; } else if (milliseconds < 60000) { return `${Math.round(milliseconds / 1000)}s`; } else { return `${Math.round(milliseconds / 60000)}m`; } } /** * Validate and normalize email data size */ export function validateEmailSize(emailData, maxSize) { const size = Buffer.byteLength(emailData, 'utf8'); return !maxSize || size <= maxSize; } /** * Clean sensitive data from logs */ export function sanitizeForLogging(data) { if (typeof data !== 'object' || data === null) { return data; } const sanitized = { ...data }; const sensitiveFields = ['password', 'pass', 'accessToken', 'refreshToken', 'clientSecret']; for (const field of sensitiveFields) { if (field in sanitized) { sanitized[field] = '[REDACTED]'; } } return sanitized; } /** * Calculate exponential backoff delay */ export function calculateBackoffDelay(attempt, baseDelay = 1000) { return Math.min(baseDelay * Math.pow(2, attempt - 1), 30000); // Max 30 seconds } /** * Parse enhanced status code */ export function parseEnhancedStatusCode(code) { const match = code.match(/^(\d)\.(\d)\.(\d)$/); if (!match) { return null; } return { class: parseInt(match[1], 10), subject: parseInt(match[2], 10), detail: parseInt(match[3], 10) }; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3RzL21haWwvZGVsaXZlcnkvc210cGNsaWVudC91dGlscy9oZWxwZXJzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRztBQUVILE9BQU8sRUFBRSxVQUFVLEVBQUUsY0FBYyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRzNFOztHQUVHO0FBQ0gsTUFBTSxVQUFVLGlCQUFpQixDQUFDLElBQVk7SUFDNUMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN6QyxNQUFNLFNBQVMsR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDM0IsTUFBTSxLQUFLLEdBQUcsU0FBUyxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsYUFBYSxDQUFDLENBQUM7SUFFNUQsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ1gsT0FBTztZQUNMLElBQUksRUFBRSxHQUFHO1lBQ1QsT0FBTyxFQUFFLHlCQUF5QjtZQUNsQyxHQUFHLEVBQUUsSUFBSTtTQUNWLENBQUM7SUFDSixDQUFDO0lBRUQsTUFBTSxJQUFJLEdBQUcsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNwQyxNQUFNLFNBQVMsR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDM0IsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFFL0QsaUNBQWlDO0lBQ2pDLE1BQU0sYUFBYSxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLGVBQWUsQ0FBQyxDQUFDO0lBQ3BFLE1B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