import { pathToFileURL } from 'node:url'; import { parseAPI, ParseAPIError } from '@parseapi/sdk'; function errorResult(error) { return error instanceof ParseAPIError ? { code: error.code, status: error.status, request_id: error.requestId } : { code: 'request_failed', status: null, request_id: null }; } function readCore(data, input) { if (!data || typeof data.valid !== 'boolean' || typeof data.email !== 'string' || data.email.toLowerCase() !== input.toLowerCase()) throw new Error('Unexpected email response.'); for (const field of ['domain_valid', 'disposable', 'role']) { if (data[field] != null && typeof data[field] !== 'boolean') throw new Error('Unexpected email flag.'); } return { email: data.email, valid: data.valid, domain_valid: data.domain_valid ?? null, disposable: data.disposable ?? null, role: data.role ?? null, suggestion: typeof data.didyoumean === 'string' ? data.didyoumean : null }; } export function readVerification(data) { if (data.deep == null || (typeof data.deep === 'object' && !Array.isArray(data.deep) && Object.keys(data.deep).length === 0)) { return { status: 'unavailable', deliverable: null, catchall: null }; } if (typeof data.deep !== 'object' || Array.isArray(data.deep)) throw new Error('Unexpected verification response.'); const { deliverable = null, catchall = null } = data.deep; if (![deliverable, catchall].every(value => value === null || typeof value === 'boolean')) { throw new Error('Unexpected verification flag.'); } // example:result const status = catchall === true ? 'catchall' : deliverable === false ? 'undeliverable' : deliverable === true && catchall === false ? 'deliverable' : 'unknown'; return { status, deliverable, catchall }; // /example:result } export async function verifyEmail(input, parse, verify = false) { if (typeof verify !== 'boolean') throw new Error('Verification must be explicitly true or false.'); if (typeof input !== 'string' || !input.trim() || input.trim().length > 254 || /[\r\n]/.test(input)) { throw new Error('Provide one email address of at most 254 characters.'); } const email = input.trim(); const result = { input, email: null, valid: null, domain_valid: null, disposable: null, role: null, suggestion: null, verification: { status: 'not_requested', deliverable: null, catchall: null }, error: null }; let core; try { // example:core core = readCore(await parse.email(email, { retries: 0 }), email); Object.assign(result, core); // /example:core } catch (error) { result.error = errorResult(error); return result; } if (!core.valid) { result.verification.status = 'skipped_invalid'; return result; } if (verify !== true) return result; // Reach this branch only after the caller explicitly requests verification. try { // example:request const data = await parse.email(email, { deep: true, retries: 0, timeoutMs: 30000 }); // /example:request readCore(data, email); if (data.valid !== true) { result.verification = { status: 'unknown', deliverable: null, catchall: null }; } else { result.verification = readVerification(data); } } catch (error) { result.verification = { status: 'request_failed', deliverable: null, catchall: null }; result.error = errorResult(error); // A timeout can follow a completed check. Let the caller decide about another attempt. } return result; } async function main() { const args = process.argv.slice(2); if (args.includes('--help')) { console.log('Use: node verify-email-server.node.mjs [email] [--verify]\nDefault: core validation of hello@example.com. --verify requests a metered check.'); return; } const verify = args.includes('--verify'); const values = args.filter(value => value !== '--verify'); if (values.length > 1 || args.filter(value => value === '--verify').length > 1 || values.some(value => value.startsWith('--'))) { throw new Error('Use: node verify-email-server.node.mjs [email] [--verify]'); } // Reads PARSEAPI_KEY. Keep the secret key in your server environment. const parse = parseAPI(undefined, { timeoutMs: 10000, retries: 0 }); const result = await verifyEmail(values[0] ?? 'hello@example.com', parse, verify); console.log(JSON.stringify(result, null, 2)); if (result.error || ['unavailable', 'unknown', 'catchall'].includes(result.verification.status)) process.exitCode = 2; } if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { main().catch(error => { console.error(error instanceof ParseAPIError ? 'Could not initialize the API client.' : error.message); process.exitCode = 1; }); }