import { serve } from "https://deno.land/std@0.190.0/http/server.ts"; import { startRequest, endRequest, edgeLogger } from "../_shared/logger.ts"; const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type, x-request-id', }; // Comprehensive list of disposable email domains const DISPOSABLE_DOMAINS = new Set([ // Popular disposable email services 'tempmail.com', 'temp-mail.org', 'temp-mail.io', 'temp-mail.de', '10minutemail.com', '10minutemail.net', '10minemail.com', 'guerrillamail.com', 'guerrillamail.net', 'guerrillamailblock.com', 'mailinator.com', 'mailinator.net', 'mailinator2.com', 'throwaway.email', 'throwemail.com', 'throwawaymail.com', 'yopmail.com', 'yopmail.fr', 'yopmail.net', 'maildrop.cc', 'mailnesia.com', 'trashmail.com', 'fakeinbox.com', 'fakemail.net', 'fakemailgenerator.com', 'getnada.com', 'getairmail.com', 'dispostable.com', 'mintemail.com', 'mytemp.email', 'mohmal.com', 'sharklasers.com', 'grr.la', 'guerrillamail.biz', 'spam4.me', 'tempinbox.com', 'tempr.email', 'emailondeck.com', 'mailcatch.com', 'mailexpire.com', 'mailforspam.com', 'mailfreeonline.com', 'mailin8r.com', 'mailmoat.com', 'mailnull.com', 'mailsac.com', 'mailscrap.com', 'mailslite.com', 'mailtemp.info', 'mailtothis.com', 'mailzi.ru', 'mytrashmail.com', 'no-spam.ws', 'noclickemail.com', 'nodezine.com', 'nospam.ze.tc', 'nospamfor.us', 'nowmymail.com', 'objectmail.com', 'obobbo.com', 'oneoffemail.com', 'onewaymail.com', 'online.ms', 'oopi.org', 'ordinaryamerican.net', 'otherinbox.com', 'owlpic.com', 'pancakemail.com', 'pjjkp.com', 'plexolan.de', 'poofy.org', 'pookmail.com', 'privacy.net', 'proxymail.eu', 'prtnx.com', 'putthisinyourspamdatabase.com', 'quickinbox.com', 'rcpt.at', 'recode.me', 'recursor.net', 'regbypass.com', 'regspaces.tk', 'rklips.com', 'rmqkr.net', 'robertspcrepair.com', 'royal.net', 'ruffrey.com', 's0ny.net', 'safersignup.de', 'safetymail.info', 'safetypost.de', 'sandelf.de', 'saynotospams.com', 'schafmail.de', 'schrott-email.de', 'secretemail.de', 'secure-mail.biz', 'senseless-entertainment.com', 'services391.com', 'sharklasers.com', 'shiftmail.com', 'shippingterms.org', 'showslow.de', 'sibmail.com', 'sinnlos-mail.de', 'slapsfromlastnight.com', 'slaskpost.se', 'smashmail.de', 'smellfear.com', 'snakemail.com', 'sneakemail.com', 'sneakmail.de', 'snkmail.com', 'sofimail.com', 'solvemail.info', 'sogetthis.com', 'soodonims.com', 'spam.la', 'spam.su', 'spamail.de', 'spamarrest.com', 'spambob.com', 'spambog.com', 'spambog.de', 'spambox.us', 'spamcannon.com', 'spamcannon.net', 'spamcero.com', 'spamcon.org', 'spamcorptastic.com', 'spamcowboy.com', 'spamcowboy.net', 'spamcowboy.org', 'spamday.com', 'spamex.com', 'spamfree24.com', 'spamfree24.de', 'spamfree24.org', 'spamgourmet.com', 'spamherelots.com', 'spamhereplease.com', 'spamhole.com', 'spamify.com', 'spaminator.de', 'spamkill.info', ]); interface ValidateEmailRequest { email: string; } interface ValidationResult { valid: boolean; reason?: string; suggestions?: string[]; } const handler = async (req: Request): Promise => { // Handle CORS preflight requests if (req.method === 'OPTIONS') { return new Response(null, { headers: corsHeaders }); } const tracking = startRequest('validate-email'); try { const { email }: ValidateEmailRequest = await req.json(); if (!email || typeof email !== 'string') { endRequest(tracking, 400, 'Email address is required'); return new Response( JSON.stringify({ valid: false, reason: 'Email address is required', requestId: tracking.requestId } as ValidationResult), { status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json', 'X-Request-ID': tracking.requestId } } ); } // Basic email format validation const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(email)) { endRequest(tracking, 400, 'Invalid email format'); return new Response( JSON.stringify({ valid: false, reason: 'Invalid email format', requestId: tracking.requestId } as ValidationResult), { status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json', 'X-Request-ID': tracking.requestId } } ); } // Extract domain const domain = email.split('@')[1].toLowerCase(); // Check if domain is disposable if (DISPOSABLE_DOMAINS.has(domain)) { edgeLogger.info('Blocked disposable email domain', { domain, requestId: tracking.requestId }); endRequest(tracking, 400, 'Disposable email domain blocked'); return new Response( JSON.stringify({ valid: false, reason: 'Disposable email addresses are not allowed. Please use a permanent email address.', suggestions: [ 'Use a personal email (Gmail, Outlook, Yahoo, etc.)', 'Use your work or school email address', 'Use an email from your own domain' ], requestId: tracking.requestId } as ValidationResult), { status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json', 'X-Request-ID': tracking.requestId } } ); } // Email is valid edgeLogger.info('Email validated successfully', { email, requestId: tracking.requestId }); endRequest(tracking, 200); return new Response( JSON.stringify({ valid: true, requestId: tracking.requestId } as ValidationResult), { status: 200, headers: { ...corsHeaders, 'Content-Type': 'application/json', 'X-Request-ID': tracking.requestId } } ); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); edgeLogger.error('Error in validate-email function', { error: errorMessage, requestId: tracking.requestId }); endRequest(tracking, 500, error.message); return new Response( JSON.stringify({ valid: false, reason: 'Internal server error during email validation', requestId: tracking.requestId } as ValidationResult), { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json', 'X-Request-ID': tracking.requestId } } ); } }; serve(handler);