Email Verifier: NeoVerify
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NEOVERIFY - Email Validation</title>
<style>
:root {
--dark-bg: #0a0a12;
--neon-blue: #00f9ff;
--neon-pink: #ff0066;
--cyber-green: #00ff9d;
--light-bg: #f5f5f7;
--light-text: #333;
--light-accent: #3366ff;
}
body {
background: var(--dark-bg);
color: white;
font-family: 'Courier New', monospace;
margin: 0;
padding: 20px;
transition: background 0.3s, color 0.3s;
}
body.light-mode {
background: var(--light-bg);
color: var(--light-text);
}
.container {
max-width: 1000px;
margin: 0 auto;
}
h1 {
color: var(--neon-blue);
text-align: center;
}
.light-mode h1 {
color: var(--light-accent);
}
textarea {
width: 100%;
height: 150px;
background: rgba(255, 255, 255, 0.1);
color: white;
border: 1px solid var(--neon-blue);
padding: 10px;
border-radius: 4px;
font-family: 'Courier New', monospace;
margin-bottom: 10px;
}
.light-mode textarea {
background: var(--light-bg);
border: 1px solid var(--light-accent);
color: var(--light-text);
}
button {
background: var(--neon-blue);
color: var(--dark-bg);
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
margin-right: 10px;
margin-bottom: 10px;
}
.light-mode button {
background: var(--light-accent);
color: white;
}
button:hover {
background: var(--neon-pink);
}
.light-mode button:hover {
background: #ff3366;
}
#results-container {
display: none;
margin-top: 20px;
}
table {
width: 100%;
border-collapse: collapse;
color: white;
}
.light-mode table {
color: var(--light-text);
}
th, td {
padding: 10px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
text-align: left;
}
.light-mode th, .light-mode td {
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
th {
background: rgba(255, 0, 102, 0.2);
}
.valid { color: var(--cyber-green); }
.invalid { color: var(--neon-pink); }
.suggestion { color: #ffea00; }
#loader {
display: none;
text-align: center;
margin: 20px 0;
color: var(--neon-blue);
}
.theme-toggle {
position: fixed;
top: 20px;
right: 20px;
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
color: var(--neon-blue);
}
.light-mode .theme-toggle {
color: var(--light-accent);
}
#email-count {
font-size: 0.9rem;
color: var(--neon-blue);
margin-bottom: 10px;
}
.light-mode #email-count {
color: var(--light-accent);
}
</style>
</head>
<body>
<button id="theme-toggle" class="theme-toggle">☀️</button>
<div class="container">
<h1>NEOVERIFY - Email Validation</h1>
<textarea id="emails" placeholder="Enter up to 100 emails (one per line or comma-separated)"></textarea>
<div id="email-count">Emails: 0 (Max: 100)</div>
<div>
<button id="verify-button">🔍 Verify Emails</button>
<button id="export-button">💾 Export CSV</button>
<button id="reset-button">🗑️ Clear</button>
</div>
<div id="loader">Validating Emails...</div>
<div id="results-container">
<h2>Validation Results</h2>
<table>
<thead>
<tr>
<th>Email</th>
<th>Status</th>
<th>Quality</th>
<th>Domain</th>
<th>Spam Risk</th>
<th>Suggestion</th>
</tr>
</thead>
<tbody id="results-body"></tbody>
</table>
</div>
</div>
<script>
const CONFIG = { maxEmails: 100, dnsDelay: 300, dnsTimeout: 5000 };
class EmailValidator {
constructor() {
this.typoDB = {
'gmail.com': ['gamil.com', 'gmial.com', 'gmal.com', 'gmali.com'],
'yahoo.com': ['yaho.com', 'yaoo.com', 'yahooo.com'],
'outlook.com': ['outlok.com', 'outook.com', 'otulook.com'],
'hotmail.com': ['hotmal.com', 'hotmai.com', 'hotmial.com'],
'aol.com': ['ao1.com', 'aol.co'],
'icloud.com': ['iclod.com', 'icould.com']
};
this.disposableDomains = [
'mailinator.com', 'tempmail.com', '10minutemail.com', 'yopmail.com',
'guerrillamail.com', 'sharklasers.com', 'dispostable.com', 'maildrop.cc',
'throwawaymail.com', 'temp-mail.org'
];
this.roleAccounts = [
'admin', 'support', 'info', 'contact', 'help', 'sales', 'marketing',
'billing', 'webmaster', 'noreply', 'no-reply', 'team'
];
this.validTLDs = [
'com', 'net', 'org', 'edu', 'gov', 'mil', 'io', 'co', 'ai', 'app',
'dev', 'me', 'info', 'online', 'biz', 'uk', 'de', 'fr', 'jp', 'ca',
'au', 'ru', 'ch', 'it', 'nl', 'se', 'no', 'es', 'cn', 'in', 'br'
];
this.dnsCache = new Map();
['gmail.com', 'yahoo.com', 'outlook.com', 'hotmail.com', 'aol.com', 'icloud.com']
.forEach(d => this.dnsCache.set(d, true));
}
async checkMxRecords(domain) {
if (this.dnsCache.has(domain)) return this.dnsCache.get(domain);
await new Promise(resolve => setTimeout(resolve, CONFIG.dnsDelay));
const controllers = [];
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('DNS timeout')), CONFIG.dnsTimeout);
});
// Try Google DNS
let googleController = new AbortController();
controllers.push(googleController);
const googlePromise = fetch(`https://dns.google/resolve?name=${domain}&type=MX`, {
headers: { 'Accept': 'application/dns-json' },
signal: googleController.signal
})
.then(response => response.ok ? response.json() : Promise.reject())
.then(data => {
const hasMx = data.Answer && data.Answer.length > 0;
this.dnsCache.set(domain, hasMx);
return hasMx;
})
.catch(() => null);
// Try Cloudflare DNS
let cloudflareController = new AbortController();
controllers.push(cloudflareController);
const cloudflarePromise = fetch(`https://cloudflare-dns.com/dns-query?name=${domain}&type=MX`, {
headers: { 'Accept': 'application/dns-json' },
signal: cloudflareController.signal
})
.then(response => response.ok ? response.json() : Promise.reject())
.then(data => {
const hasMx = data.Answer && data.Answer.length > 0;
this.dnsCache.set(domain, hasMx);
return hasMx;
})
.catch(() => null);
try {
const result = await Promise.race([
Promise.any([googlePromise, cloudflarePromise]),
timeoutPromise
]);
controllers.forEach(c => c.abort());
if (result !== null) return result;
} catch (err) {
controllers.forEach(c => c.abort());
}
this.dnsCache.set(domain, false);
return false;
}
checkForTypos(user, domain) {
for (const [correct, typos] of Object.entries(this.typoDB)) {
if (typos.includes(domain)) return `${user}@${correct}`;
}
return null;
}
async validateEmail(email) {
const emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/;
if (!emailRegex.test(email)) {
return { email, valid: false, reason: "Invalid format", quality: "invalid" };
}
const [user, domain] = email.split('@');
if (user.length < 2 || user.startsWith('.') || user.endsWith('.') || user.includes('..')) {
return { email, valid: false, reason: "Invalid username", quality: "invalid" };
}
const tld = domain.split('.').pop().toLowerCase();
const hasTLD = this.validTLDs.includes(tld);
if (!hasTLD) {
return { email, valid: false, reason: "Invalid TLD", quality: "invalid" };
}
const hasMx = await this.checkMxRecords(domain);
const suggestion = this.checkForTypos(user, domain);
const isDisposable = this.disposableDomains.includes(domain);
const isRole = this.roleAccounts.some(r => user.toLowerCase().startsWith(r) || user.toLowerCase() === r);
const isRandom = /^\d+$/.test(user) || (user.match(/\d/g)?.length > user.length / 2 && user.length > 8);
let quality = "invalid";
let spamRisk = "Low";
if (hasMx && hasTLD) {
if (isDisposable || isRandom) {
quality = "risky";
spamRisk = "High";
} else if (isRole) {
quality = "standard";
spamRisk = "Medium";
} else {
quality = "premium";
}
}
return {
email,
valid: hasMx && hasTLD,
quality,
domain,
spamRisk,
suggestion,
reason: !hasTLD ? "Invalid TLD" : !hasMx ? "No MX Records" : null
};
}
async validateBatch(emails, onProgress) {
const results = [];
const batchSize = Math.min(emails.length, CONFIG.maxEmails);
const chunkSize = 5;
for (let i = 0; i < batchSize; i += chunkSize) {
const chunk = emails.slice(i, Math.min(i + chunkSize, batchSize));
const chunkResults = await Promise.all(chunk.map(email => this.validateEmail(email)));
results.push(...chunkResults);
if (onProgress) onProgress(Math.min(i + chunkSize, batchSize), batchSize);
await new Promise(resolve => setTimeout(resolve, 10));
}
return results;
}
}
class App {
constructor() {
this.validator = new EmailValidator();
this.results = [];
this.isLightMode = false;
}
init() {
document.getElementById('verify-button').addEventListener('click', () => this.runValidation());
document.getElementById('reset-button').addEventListener('click', () => this.clearAll());
document.getElementById('export-button').addEventListener('click', () => this.exportResults());
document.getElementById('theme-toggle').addEventListener('click', () => this.toggleTheme());
document.getElementById('emails').addEventListener('input', () => this.countEmails());
if (localStorage.getItem('theme') === 'light') this.toggleTheme();
this.countEmails();
}
toggleTheme() {
document.body.classList.toggle('light-mode');
this.isLightMode = document.body.classList.contains('light-mode');
document.getElementById('theme-toggle').textContent = this.isLightMode ? '🌙' : '☀️';
localStorage.setItem('theme', this.isLightMode ? 'light' : 'dark');
}
getEmails() {
return document.getElementById('emails').value
.split(/[\n,;]+/)
.map(e => e.trim())
.filter(e => e && e.includes('@'));
}
countEmails() {
const emails = this.getEmails();
document.getElementById('email-count').textContent = `Emails: ${emails.length} (Max: ${CONFIG.maxEmails})`;
return emails;
}
async runValidation() {
const emails = this.countEmails();
if (!emails.length) {
alert('Please enter at least one email!');
return;
}
if (emails.length > CONFIG.maxEmails) {
alert(`Validation limited to ${CONFIG.maxEmails} emails.`);
emails.splice(CONFIG.maxEmails);
}
this.showLoading(true);
this.results = await this.validator.validateBatch(emails, (processed, total) => {
document.getElementById('loader').textContent = `Validating ${processed}/${total} Emails...`;
});
this.displayResults();
this.showLoading(false);
}
showLoading(show) {
document.getElementById('loader').style.display = show ? 'block' : 'none';
document.getElementById('verify-button').disabled = show;
}
displayResults() {
const tbody = document.getElementById('results-body');
tbody.innerHTML = this.results.map(r => `
<tr>
<td>${r.email}</td>
<td class="${r.valid ? 'valid' : 'invalid'}">${r.valid ? 'Valid' : 'Invalid'}${r.reason ? ` (${r.reason})` : ''}</td>
<td>${r.quality}</td>
<td>${r.domain}</td>
<td>${r.spamRisk}</td>
<td class="${r.suggestion ? 'suggestion' : ''}">${r.suggestion || '—'}</td>
</tr>
`).join('');
document.getElementById('results-container').style.display = 'block';
}
exportResults() {
if (!this.results.length) {
alert('No results to export!');
return;
}
const headers = ['Email', 'Status', 'Quality', 'Domain', 'Spam Risk', 'Suggestion'];
let csv = headers.join(',') + '\n';
this.results.forEach(r => {
csv += [
`"${r.email}"`,
r.valid ? 'Valid' : `Invalid${r.reason ? ` (${r.reason})` : ''}`,
r.quality,
r.domain,
r.spamRisk,
r.suggestion || ''
].join(',') + '\n';
});
const blob = new Blob([csv], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'email_validation_results.csv';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
clearAll() {
document.getElementById('emails').value = '';
document.getElementById('results-container').style.display = 'none';
this.results = [];
this.countEmails();
}
}
const app = new App();
document.addEventListener('DOMContentLoaded', () => app.init());
</script>
</body>
</html>
Comments
Post a Comment