Email Separator

 <!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Ultimate Email Domain Separator - The Most Comprehensive Tool</title>
    <meta name="description" content="The ultimate email domain separator, organizing each domain extension in its own boxed-in area, supporting all ccTLDs, regional SLDs, gTLDs, webmails, and temporary domains with DMARC compatibility checks and mobile-first design.">
    <meta name="keywords" content="email separator, email organizer, email domain separator, ccTLD, regional SLD, temporary email, DMARC, email security, mobile responsive">
    <link href="https://fonts.googleapis.com/css2?family=Baloo+Bhaijaan+2:wght@400;500;600;700&display=swap" rel="stylesheet">
    <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>✅</text></svg>">
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/css/toastr.min.css" />
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        :root {
            --primary: #3b82f6;
            --success: #28a745;
            --warning: #ffc107;
            --danger: #dc3545;
            --info: #17a2b8;
            --purple: #6f42c1;
            --gray: #6c757d;
            --dark: #343a40;
            --light: #f8f9fa;
        }
        body {
            background-color: var(--light);
            font-family: 'Baloo Bhaijaan 2', sans-serif;
            color: #333;
            display: flex;
            flex-direction: column;
            min-height: 100vh;
            overscroll-behavior: none;
        }
        .content { flex: 1; margin-bottom: 40px; }
        .domain-card {
            background: #fff;
            border-radius: 12px;
            border: 1px solid #e5e7eb;
            transition: transform 0.3s, box-shadow 0.3s;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        }
        .domain-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
        }
        .domain-card-header {
            background-color: var(--primary);
            color: #fff;
            padding: 12px;
            border-top-left-radius: 12px;
            border-top-right-radius: 12px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            font-size: 1rem;
            white-space: normal;
            word-break: break-word;
        }
        .domain-card-header-actions {
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .domain-card-header-actions .btn {
            padding: 0;
            width: 40px;
            height: 40px;
            display: flex;
            justify-content: center;
            align-items: center;
            background: none;
            border: none;
            color: #fff;
            transition: background-color 0.3s;
        }
        .domain-card-header-actions .btn:hover {
            background-color: rgba(255, 255, 255, 0.2);
        }
        .domain-card-header-actions .btn-danger { color: #ff4d4d; }
        .domain-card-header-actions .badge {
            background-color: rgba(255, 255, 255, 0.3);
            color: #fff;
            font-size: 0.9rem;
            padding: 0.3rem 0.6rem;
            border-radius: 12px;
        }
        .input-group {
            background-color: rgba(59, 130, 246, 0.1);
            border-radius: 10px;
            border: 1px solid var(--primary);
        }
        .btn:hover:not(:disabled) {
            background-color: #2563eb;
            transform: scale(1.05);
        }
        footer {
            border-top-left-radius: 30px;
            border-top-right-radius: 30px;
            background-color: #e9ecef;
            padding: 3rem 0;
            margin-top: auto;
            color: #333;
        }
        .paste-area {
            width: 100%;
            min-height: 120px;
            padding: 1rem;
            background: rgba(255, 255, 255, 0.9);
            border: 1px solid #e5e7eb;
            border-radius: 10px;
            color: #333;
            font-size: 1rem;
            resize: vertical;
        }
        .paste-area:focus {
            outline: none;
            border-color: var(--primary);
            box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2);
        }
        .email-count {
            color: #4b5563;
            font-size: 1rem;
            margin-top: 0.5rem;
        }
        .results-grid {
            display: grid;
            gap: 1.5rem;
            margin-top: 2rem;
        }
        .stats-panel {
            background: #fff;
            border-radius: 10px;
            padding: 1.5rem;
            margin-bottom: 1.5rem;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }
        .filter-controls, .sort-controls {
            margin: 1.5rem 0;
            display: flex;
            gap: 1rem;
            flex-wrap: wrap;
            justify-content: center;
        }
        .filter-list {
            display: flex;
            flex-direction: column;
            gap: 0.5rem;
        }
        .search-bar {
            max-width: 400px;
            margin: 1.5rem auto;
        }
        .badge-ccTLD { background-color: var(--success); }
        .badge-regional-sld { background-color: var(--warning); }
        .badge-gTLD { background-color: var(--info); }
        .badge-webmail { background-color: var(--purple); }
        .badge-temporary { background-color: var(--danger); }
        .badge-custom { background-color: var(--gray); }
        .badge-invalid { background-color: var(--dark); }
        .tooltip-content {
            display: none;
            position: absolute;
            bottom: 100%;
            left: 50%;
            transform: translateX(-50%);
            background: rgba(0, 0, 0, 0.9);
            padding: 0.75rem;
            border-radius: 8px;
            width: max-content;
            max-width: 300px;
            z-index: 1000;
            margin-bottom: 0.5rem;
            font-size: 0.9rem;
            color: #fff;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
        }
        .badge.tapped .tooltip-content { display: block; }
        .validation-tools {
            margin-top: 1.5rem;
            padding: 1.5rem;
            background: #f1f5f9;
            border-radius: 12px;
        }
        .validation-input {
            width: 100%;
            padding: 12px 15px;
            border: 2px solid #e2e8f0;
            border-radius: 8px;
            margin-bottom: 10px;
            font-family: monospace;
            font-size: 1rem;
        }
        .validation-result-simple {
            padding: 10px;
            border-radius: 6px;
            margin-top: 10px;
            font-weight: 500;
            font-size: 0.95rem;
        }
        .valid-bg { background-color: #d1fae5; color: #065f46; }
        .warning-bg { background-color: #fef3c7; color: #92400e; }
        .invalid-bg { background-color: #fee2e2; color: #991b1b; }
        .chart-container {
            max-width: 100%;
            margin: 1.5rem auto;
            padding: 1rem;
            background: #fff;
            border-radius: 10px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }
        .high-contrast body { background: #000; color: #fff; }
        .high-contrast .domain-card { background: #222; color: #fff; }
        .high-contrast .domain-card-header { background: #005bb5; }
        .high-contrast .badge-ccTLD { background: #00cc00; }
        .high-contrast .badge-regional-sld { background: #ffeb3b; color: #000; }
        .high-contrast .badge-gTLD { background: #00bcd4; }
        .high-contrast .badge-webmail { background: #ab47bc; }
        .high-contrast .badge-temporary { background: #d32f2f; }
        .high-contrast .badge-custom { background: #757575; }
        .high-contrast .badge-invalid { background: #212121; }
        .high-contrast .stats-panel, .high-contrast .validation-tools { background: #333; color: #fff; }
        @keyframes slideIn {
            from { opacity: 0; transform: translateY(20px); }
            to { opacity: 1; transform: translateY(0); }
        }
        @media (max-width: 768px) {
            .paste-area { min-height: 100px; }
            .filter-controls, .sort-controls { flex-direction: column; align-items: center; }
            .domain-card-container { width: 100%; }
            .search-bar { max-width: 100%; }
            .stats-panel .row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
            .d-flex.gap-2 { gap: 0.5rem; flex-wrap: wrap; justify-content: center; }
            .domain-card-header { font-size: 0.95rem; }
            .domain-card-header-actions .badge { font-size: 0.85rem; }
            .filter-list { display: none; }
            .filter-list.show { display: flex; }
            .btn { font-size: 0.9rem; padding: 10px; }
        }
        @media (max-width: 480px) {
            .stats-panel .row { grid-template-columns: 1fr; }
            .domain-card-header { font-size: 0.9rem; }
        }
    </style>
</head>
<body>
    <div class="content">
        <div class="container" style="margin-top: 50px;">
            <div class="mb-4 d-flex justify-content-between align-items-center flex-wrap gap-2">
                <a href="https://www.eml.ist/" class="btn" style="background-color: #ffffff; color: #333; border: 2px solid var(--primary);">
                    <i class="fas fa-arrow-left me-2"></i>Back to Tools
                </a>
                <button class="btn toggle-contrast" style="background-color: #ffffff; color: #333; border: 2px solid var(--primary);">
                    <i class="fas fa-adjust me-2"></i>Toggle High Contrast
                </button>
            </div>

            <div class="container mx-auto px-4 py-8">
                <div class="max-w-4xl mx-auto">
                    <h1 class="text-5xl font-bold text-center mb-4" style="color: var(--primary);">Ultimate Email Domain Separator</h1>
                    <p class="text-center mb-8 text-gray-600">Each domain extension in its own boxed-in area, supporting all ccTLDs, regional SLDs, gTLDs, webmails, and temporary domains with DMARC compatibility checks.</p>

                    <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
                        <div class="feature-card p-6 rounded-lg shadow-lg">
                            <div class="text-3xl mb-3">🌍</div>
                            <h2 class="font-bold mb-2" style="color: var(--primary);">Universal Domain Support</h2>
                            <p class="text-sm text-gray-600">Each extension in its own boxed-in area, covering all ccTLDs, SLDs, and more.</p>
                        </div>
                        <div class="feature-card p-6 rounded-lg shadow-lg">
                            <div class="text-3xl mb-3">⚙️</div>
                            <h2 class="font-bold mb-2" style="color: var(--primary);">Advanced Filtering & Sorting</h2>
                            <p class="text-sm text-gray-600">Filter by category, SLD, search, and sort with DMARC insights.</p>
                        </div>
                        <div class="feature-card p-6 rounded-lg shadow-lg">
                            <div class="text-3xl mb-3">📤</div>
                            <h2 class="font-bold mb-2" style="color: var(--primary);">Flexible Export & Security</h2>
                            <p class="text-sm text-gray-600">Export as TXT, CSV, JSON with DMARC compatibility checks.</p>
                        </div>
                    </div>
                </div>
            </div>

            <div class="card" style="background-color: var(--primary); border: none; border-radius: 12px; box-shadow: 0px 8px 15px rgba(0, 0, 0, 0.1); margin-bottom: 30px; max-width: 800px; width: 100%; margin-left: auto; margin-right: auto;">
                <div class="card-body">
                    <form id="emailSeparatorForm">
                        <div class="mb-3">
                            <input type="file" id="importFile" accept=".txt,.csv" class="form-control mb-3" aria-label="Upload email list">
                            <textarea id="emailInput" class="form-control paste-area" rows="8" placeholder="Paste your emails here (one per line, comma-separated, or custom delimiter)..." aria-label="Email input"></textarea>
                        </div>
                        <div class="row mb-3">
                            <div class="col-md-6">
                                <small style="color: rgba(255, 255, 255, 0.75);">Email Count: <span id="emailCount">0</span> | Duplicates Removed: <span id="duplicateCount">0</span></small>
                            </div>
                            <div class="col-md-6">
                                <select id="emailDelimiter" class="form-select" aria-label="Delimiter selection">
                                    <option value="\n">New Line ( \n )</option>
                                    <option value=", ">Comma ( , )</option>
                                    <option value="|">Pipe ( | )</option>
                                    <option value=" : ">Colon ( : )</option>
                                    <option value="other">Custom</option>
                                </select>
                            </div>
                        </div>
                        <div id="customDelimiterWrapper" style="display: none;" class="mb-3">
                            <input type="text" id="customDelimiter" class="form-control" placeholder="Enter your custom delimiter" aria-label="Custom delimiter" />
                        </div>
                        <div class="d-flex justify-content-between flex-wrap gap-2">
                            <button type="button" class="btn" id="btnSeparate" style="background-color: #fff; color: var(--primary);"><i class="fas fa-filter"></i> Separate Domains</button>
                            <button type="button" class="btn" id="btnCopyAll" style="background-color: #fff; color: var(--primary);"><i class="fas fa-copy"></i> Copy All</button>
                            <button type="button" class="btn" id="btnDownloadTxt" style="background-color: #fff; color: var(--primary);"><i class="fas fa-download"></i> TXT</button>
                            <button type="button" class="btn" id="btnDownloadCsv" style="background-color: #fff; color: var(--primary);"><i class="fas fa-file-csv"></i> CSV</button>
                            <button type="button" class="btn" id="btnDownloadJson" style="background-color: #fff; color: var(--primary);"><i class="fas fa-file-code"></i> JSON</button>
                            <button type="reset" class="btn" style="border: 1px solid #fff; color: #fff;" id="btnReset"><i class="fas fa-refresh"></i> Reset</button>
                        </div>
                    </form>
                </div>
            </div>

            <div class="stats-panel">
                <h3 class="text-center mb-3">Statistics</h3>
                <div class="row text-center">
                    <div class="col-md-3"><strong>ccTLDs</strong>: <span id="statsCcTLD">0</span></div>
                    <div class="col-md-3"><strong>Regional SLDs</strong>: <span id="statsRegionalSld">0</span></div>
                    <div class="col-md-3"><strong>Webmails</strong>: <span id="statsWebmail">0</span></div>
                    <div class="col-md-3"><strong>Temporary</strong>: <span id="statsTemporary">0</span></div>
                </div>
                <div class="chart-container">
                    <canvas id="statsChart"></canvas>
                </div>
            </div>

            <div class="validation-tools">
                <h3>🔍 DMARC Compatibility Check</h3>
                <p>Check SPF/DKIM syntax for selected domains (client-side, no DNS lookup):</p>
                <div class="form-group">
                    <label for="spf-input">SPF Record</label>
                    <input type="text" id="spf-input" class="validation-input" placeholder="v=spf1 include:_spf.example.com ~all" aria-label="SPF record input">
                    <button class="btn btn-primary" onclick="validateSPF()" style="width: 100%; margin-bottom: 15px;">Validate SPF</button>
                    <div id="spf-result" class="validation-result-simple"></div>
                </div>
                <div class="form-group">
                    <label for="dkim-input">DKIM Record</label>
                    <input type="text" id="dkim-input" class="validation-input" placeholder="v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3..." aria-label="DKIM record input">
                    <button class="btn btn-primary" onclick="validateDKIM()" style="width: 100%;">Validate DKIM</button>
                    <div id="dkim-result" class="validation-result-simple"></div>
                </div>
            </div>

            <div class="filter-controls">
                <button class="btn toggle-filters" style="background-color: #fff; color: var(--primary);"><i class="fas fa-filter"></i> Toggle Filters</button>
                <div class="filter-list">
                    <label><input type="checkbox" class="filter-category" value="ccTLD" checked> ccTLD</label>
                    <label><input type="checkbox" class="filter-category" value="regional-sld" checked> Regional SLD</label>
                    <label><input type="checkbox" class="filter-category" value="gTLD" checked> gTLD</label>
                    <label><input type="checkbox" class="filter-category" value="webmail" checked> Webmail</label>
                    <label><input type="checkbox" class="filter-category" value="temporary" checked> Temporary</label>
                    <label><input type="checkbox" class="filter-category" value="custom" checked> Custom</label>
                    <label><input type="checkbox" class="filter-category" value="invalid" checked> Invalid</label>
                </div>
                <input type="text" id="filterSld" class="form-control search-bar" placeholder="Filter by SLD (e.g., yahoo)..." aria-label="SLD filter">
            </div>

            <input type="text" id="searchDomains" class="form-control search-bar" placeholder="Search domains (e.g., .co.uk, gmail)..." aria-label="Domain search">

            <div class="sort-controls">
                <select id="sortBy" class="form-select" style="max-width: 200px;" aria-label="Sort selection">
                    <option value="name">Sort by Name</option>
                    <option value="count">Sort by Count</option>
                    <option value="category">Sort by Category</option>
                </select>
                <button id="sortAsc" class="btn btn-sm active" style="background-color: #fff; color: var(--primary);"><i class="fas fa-sort-alpha-down"></i> Asc</button>
                <button id="sortDesc" class="btn btn-sm" style="background-color: #fff; color: var(--primary);"><i class="fas fa-sort-alpha-up"></i> Desc</button>
            </div>

            <div id="domainResults" class="row g-4"></div>
        </div>
    </div>

    <footer>
        <div class="container">
            <div class="row d-flex align-items-center justify-content-between">
                <div class="col-md-4 d-inline-flex align-items-center">
                    <h5 class="mb-0"><a href="https://eml.ist" style="color: var(--primary); text-decoration: none;">Email Tools</a></h5>
                </div>
                <div class="col-md-4 d-inline-flex align-items-center justify-content-center"></div>
                <div class="col-md-4 d-inline-flex align-items-center justify-content-end">
                    <a href="https://eml.ist/privacy.html" class="me-3" style="color: #4b5563; text-decoration: none;">Privacy Policy</a>
                </div>
            </div>
            <div class="align-items-center d-inline-flex justify-content-center w-100 mt-3 flex-wrap gap-3">
                <a href="https://eml.ist/about.html" style="color: #4b5563;">About Us</a>
                <a href="https://eml.ist/contact.html" style="color: #4b5563;">Contact Us</a>
                <a href="https://eml.ist/faq.html" style="color: #4b5563;">FAQs</a>
                <a href="https://eml.ist/copyright.html" style="color: #4b5563;">Copyright</a>
                <a href="https://eml.ist/terms.html" style="color: #4b5563;">Terms of Use</a>
                <a href="https://eml.ist/index.html?our-tools#our-tools" style="color: #4b5563;">All Tools</a>
            </div>
            <div class="text-center mt-3" style="color: #4b5563;">
                <p>Copyright 2025. All Rights Reserved</p>
                <p style="font-size: 14px; margin-top: 8px;">
                    Website created by <a href="https://webopsx.com" target="_blank" style="color: var(--primary); text-decoration: none;">WebOpsX</a>
                </p>
            </div>
        </div>
    </footer>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/js/toastr.min.js"></script>
    <script>
        $(document).ready(function () {
            // Embedded TLD data (expanded sample)
            const tldInfo = {
                '.us': { type: 'ccTLD', manager: 'United States', display: '.US (United States)', tooltip: 'Country code for the United States' },
                '.uk': { type: 'ccTLD', manager: 'United Kingdom', display: '.UK (United Kingdom)', tooltip: 'Country code for the United Kingdom' },
                '.co.uk': { type: 'ccTLD', manager: 'United Kingdom', display: '.CO.UK (United Kingdom)', tooltip: 'Commercial domain for the United Kingdom' },
                '.ru': { type: 'ccTLD', manager: 'Russia', display: '.RU (Russia)', tooltip: 'Country code for Russia' },
                '.jp': { type: 'ccTLD', manager: 'Japan', display: '.JP (Japan)', tooltip: 'Country code for Japan' },
                '.co.jp': { type: 'ccTLD', manager: 'Japan', display: '.CO.JP (Japan)', tooltip: 'Commercial domain for Japan' },
                '.br': { type: 'ccTLD', manager: 'Brazil', display: '.BR (Brazil)', tooltip: 'Country code for Brazil' },
                '.com.br': { type: 'ccTLD', manager: 'Brazil', display: '.COM.BR (Brazil)', tooltip: 'Commercial domain for Brazil' },
                '.fr': { type: 'ccTLD', manager: 'France', display: '.FR (France)', tooltip: 'Country code for France' },
                '.de': { type: 'ccTLD', manager: 'Germany', display: '.DE (Germany)', tooltip: 'Country code for Germany' },
                '.it': { type: 'ccTLD', manager: 'Italy', display: '.IT (Italy)', tooltip: 'Country code for Italy' },
                '.au': { type: 'ccTLD', manager: 'Australia', display: '.AU (Australia)', tooltip: 'Country code for Australia' },
                '.com.au': { type: 'ccTLD', manager: 'Australia', display: '.COM.AU (Australia)', tooltip: 'Commercial domain for Australia' },
                '.ca': { type: 'ccTLD', manager: 'Canada', display: '.CA (Canada)', tooltip: 'Country code for Canada' },
                '.nl': { type: 'ccTLD', manager: 'Netherlands', display: '.NL (Netherlands)', tooltip: 'Country code for Netherlands' },
                '.pl': { type: 'ccTLD', manager: 'Poland', display: '.PL (Poland)', tooltip: 'Country code for Poland' },
                '.es': { type: 'ccTLD', manager: 'Spain', display: '.ES (Spain)', tooltip: 'Country code for Spain' },
                '.cn': { type: 'ccTLD', manager: 'China', display: '.CN (China)', tooltip: 'Country code for China' },
                '.in': { type: 'ccTLD', manager: 'India', display: '.IN (India)', tooltip: 'Country code for India' },
                '.рф': { type: 'ccTLD-idn', manager: 'Russia', display: '.РФ (Russia)', tooltip: 'Cyrillic domain for Russia' },
                '.za': { type: 'ccTLD', manager: 'South Africa', display: '.ZA (South Africa)', tooltip: 'Country code for South Africa' },
                '.kr': { type: 'ccTLD', manager: 'South Korea', display: '.KR (South Korea)', tooltip: 'Country code for South Korea' },
                '.mx': { type: 'ccTLD', manager: 'Mexico', display: '.MX (Mexico)', tooltip: 'Country code for Mexico' },
                '.us.com': { type: 'regional-sld', manager: 'United States (Commercial)', display: '.US.COM (US Commercial)', tooltip: 'Commercial domain mimicking US ccTLD' },
                '.uk.com': { type: 'regional-sld', manager: 'United Kingdom (Commercial)', display: '.UK.COM (UK Commercial)', tooltip: 'Commercial domain mimicking UK ccTLD' },
                '.de.com': { type: 'regional-sld', manager: 'Germany (Commercial)', display: '.DE.COM (Germany Commercial)', tooltip: 'Commercial domain mimicking Germany ccTLD' },
                '.eu.com': { type: 'regional-sld', manager: 'Europe (Commercial)', display: '.EU.COM (Europe Commercial)', tooltip: 'Commercial domain mimicking Europe ccTLD' },
                '.cn.com': { type: 'regional-sld', manager: 'China (Commercial)', display: '.CN.COM (China Commercial)', tooltip: 'Commercial domain mimicking China ccTLD' },
                '.br.com': { type: 'regional-sld', manager: 'Brazil (Commercial)', display: '.BR.COM (Brazil Commercial)', tooltip: 'Commercial domain mimicking Brazil ccTLD' },
                '.ru.com': { type: 'regional-sld', manager: 'Russia (Commercial)', display: '.RU.COM (Russia Commercial)', tooltip: 'Commercial domain mimicking Russia ccTLD' },
                '.jp.net': { type: 'regional-sld', manager: 'Japan (Commercial)', display: '.JP.NET (Japan Commercial)', tooltip: 'Commercial domain mimicking Japan ccTLD' },
                '.sa.com': { type: 'regional-sld', manager: 'Saudi Arabia (Commercial)', display: '.SA.COM (Saudi Arabia Commercial)', tooltip: 'Commercial domain mimicking Saudi Arabia ccTLD' },
                '.za.com': { type: 'regional-sld', manager: 'South Africa (Commercial)', display: '.ZA.COM (South Africa Commercial)', tooltip: 'Commercial domain mimicking South Africa ccTLD' },
                '.com': { type: 'gTLD', manager: 'Generic', display: '.COM (Generic)', tooltip: 'Generic top-level domain' },
                '.net': { type: 'gTLD', manager: 'Generic', display: '.NET (Generic)', tooltip: 'Generic top-level domain' },
                '.org': { type: 'gTLD', manager: 'Generic', display: '.ORG (Generic)', tooltip: 'Generic top-level domain' },
            };

            const majorWebmails = {
                'gmail.com': { displayName: 'Gmail.com (Webmail)', type: 'webmail', tooltip: 'Google’s email service', spf: 'v=spf1 include:_spf.google.com ~all' },
                'yahoo.com': { displayName: 'Yahoo.com (Webmail)', type: 'webmail', tooltip: 'Yahoo’s email service', spf: 'v=spf1 include:_spf.yahoo.com ~all' },
                'outlook.com': { displayName: 'Outlook.com (Webmail)', type: 'webmail', tooltip: 'Microsoft’s email service', spf: 'v=spf1 include:_spf.outlook.com ~all' },
                'hotmail.com': { displayName: 'Hotmail.com (Webmail)', type: 'webmail', tooltip: 'Microsoft’s legacy email service', spf: 'v=spf1 include:_spf.hotmail.com ~all' },
            };

            const temporaryDomains = [
                'mailinator.com', '10minutemail.com', 'trashmail.com', 'guerrillamail.com', 'temp-mail.com',
                'disposableinbox.com', 'yopmail.com', 'sharklasers.com', '20minutemail.com', '30minutemail.com',
                '60minutemail.com', 'discardmail.com', 'tempemail.net', 'throwawayemailaddress.com', 'fakemailz.com',
                'pookmail.com', 'spamgourmet.com', 'tempmail.com', 'maildrop.cc', 'getnada.com',
                'tempinbox.com', 'mailcatch.com', 'fakeinbox.com'
            ];

            let chartInstance = null;

            $("#emailDelimiter").on("change", function () {
                $("#customDelimiterWrapper").toggle($(this).val() === "other");
            });

            $('.toggle-filters').on('click', function() {
                $('.filter-list').toggleClass('show').slideToggle(200);
            });

            $('.toggle-contrast').on('click', function() {
                $('body').toggleClass('high-contrast');
                toastr.info($('body').hasClass('high-contrast') ? 'High contrast mode enabled' : 'High contrast mode disabled');
                updateChart();
            });

            $(document).on('click', '.badge', function(e) {
                e.stopPropagation();
                $('.badge').not(this).removeClass('tapped');
                $(this).toggleClass('tapped');
            });

            $(document).on('click', function(e) {
                if (!$(e.target).closest('.badge').length) {
                    $('.badge').removeClass('tapped');
                }
            });

            $("#importFile").on("change", function(e) {
                const file = e.target.files[0];
                if (!file) return;
                const reader = new FileReader();
                reader.onload = function(e) {
                    $("#emailInput").val(e.target.result);
                    $("#btnSeparate").trigger('click');
                };
                reader.readAsText(file);
                this.value = '';
            });

            $("#btnSeparate").on("click", function() {
                const inputText = $("#emailInput").val().trim();
                let inputDelimiter = $("#emailDelimiter").val();
                if (inputDelimiter === "other") {
                    inputDelimiter = $("#customDelimiter").val() || "\n";
                }
                const normalizedDelimiter = inputDelimiter === "\\n" ? "\n" : inputDelimiter;

                const emailPattern = /^[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])?)*$/gm;

                const extractedEmails = [];
                let match;
                while ((match = emailPattern.exec(inputText)) !== null) {
                    extractedEmails.push(match[0]);
                }
                const emailSet = new Set(extractedEmails.map(email => email.toLowerCase()));
                const uniqueEmails = [...emailSet];
                const duplicateCount = extractedEmails.length - uniqueEmails.length;

                $("#emailCount").text(uniqueEmails.length);
                $("#duplicateCount").text(duplicateCount);

                const domainGroups = new Map();
                const temporaryGroup = {
                    emails: [],
                    displayName: 'Temporary Emails',
                    tldInfo: { type: 'temporary', manager: 'Disposable Email Services', tooltip: 'Temporary or disposable email domains' }
                };
                const customWebmails = {
                    emails: [],
                    displayName: 'Custom Web Mails',
                    tldInfo: { type: 'custom', manager: 'Unknown Domains', tooltip: 'Domains not recognized as ccTLD, SLD, gTLD, or webmail' }
                };
                const invalidEmails = {
                    emails: [],
                    displayName: 'Invalid Emails',
                    tldInfo: { type: 'invalid', manager: 'Malformed Emails', tooltip: 'Emails with invalid or missing domains' }
                };

                uniqueEmails.forEach(email => {
                    const emailLower = email.toLowerCase();
                    const [, domain] = emailLower.split('@');
                    if (!domain || !domain.includes('.')) {
                        invalidEmails.emails.push(email);
                        return;
                    }

                    const domainParts = domain.split('.');
                    const sld = domainParts.length > 1 ? domainParts[0] : '';
                    const tld1 = '.' + domainParts.slice(-1)[0];
                    const tld2 = domainParts.length > 1 ? '.' + domainParts.slice(-2).join('.') : null;
                    const tld3 = domainParts.length > 2 ? '.' + domainParts.slice(-3).join('.') : null;
                    let groupKey, displayName, tldInfoEntry;

                    if (majorWebmails[domain]) {
                        groupKey = domain;
                        displayName = majorWebmails[domain].displayName;
                        tldInfoEntry = { ...majorWebmails[domain], manager: domain };
                        $("#spf-input").val(majorWebmails[domain].spf || '');
                    } else if (temporaryDomains.includes(domain)) {
                        temporaryGroup.emails.push(email);
                        return;
                    } else if (tld3 && tldInfo[tld3]) {
                        groupKey = tld3;
                        displayName = tldInfo[tld3].display;
                        tldInfoEntry = tldInfo[tld3];
                    } else if (tld2 && tldInfo[tld2]) {
                        groupKey = tld2;
                        displayName = tldInfo[tld2].display;
                        tldInfoEntry = tldInfo[tld2];
                    } else if (tld1 && tldInfo[tld1]) {
                        groupKey = tld1;
                        displayName = tldInfo[tld1].display;
                        tldInfoEntry = tldInfo[tld1];
                    } else {
                        if (tld3 && tld3.endsWith('.com') && tld3.split('.')[0].length === 2) {
                            groupKey = tld3;
                            displayName = `${tld3.toUpperCase()} (Potential Regional SLD)`;
                            tldInfoEntry = { type: 'regional-sld', manager: 'Unknown (Commercial)', tooltip: 'Possible commercial domain mimicking a ccTLD' };
                        } else {
                            customWebmails.emails.push(email);
                            return;
                        }
                    }

                    const sldFilter = $("#filterSld").val().toLowerCase();
                    if (sldFilter && !sld.includes(sldFilter)) {
                        return;
                    }

                    if (!domainGroups.has(groupKey)) {
                        domainGroups.set(groupKey, {
                            emails: [],
                            displayName: displayName,
                            tldInfo: tldInfoEntry
                        });
                    }
                    domainGroups.get(groupKey).emails.push(email);
                });

                updateStatistics(domainGroups, temporaryGroup, customWebmails, invalidEmails);
                $("#domainResults").empty();
                lazyRenderCards(domainGroups, temporaryGroup, customWebmails, invalidEmails, normalizedDelimiter);
                toastr.success(`Emails separated successfully! ${uniqueEmails.length} unique emails, ${duplicateCount} duplicates removed.`);
            });

            function updateStatistics(domainGroups, temporaryGroup, customWebmails, invalidEmails) {
                let ccTldCount = 0, regionalSldCount = 0, gTldCount = 0, webmailCount = 0;
                for (const [, info] of domainGroups) {
                    if (info.tldInfo.type === 'ccTLD' || info.tldInfo.type === 'ccTLD-idn') {
                        ccTldCount += info.emails.length;
                    } else if (info.tldInfo.type === 'regional-sld') {
                        regionalSldCount += info.emails.length;
                    } else if (info.tldInfo.type === 'gTLD') {
                        gTldCount += info.emails.length;
                    } else if (info.tldInfo.type === 'webmail') {
                        webmailCount += info.emails.length;
                    }
                }
                $("#statsCcTLD").text(ccTldCount);
                $("#statsRegionalSld").text(regionalSldCount);
                $("#statsWebmail").text(webmailCount);
                $("#statsTemporary").text(temporaryGroup.emails.length);
                updateChart(ccTldCount, regionalSldCount, gTldCount, webmailCount, temporaryGroup.emails.length, customWebmails.emails.length, invalidEmails.emails.length);
            }

            function updateChart(ccTldCount, regionalSldCount, gTldCount, webmailCount, tempCount, customCount, invalidCount) {
                if (chartInstance) {
                    chartInstance.destroy();
                }
                const ctx = document.getElementById('statsChart').getContext('2d');
                const isHighContrast = $('body').hasClass('high-contrast');
                chartInstance = new Chart(ctx, {
                    type: 'pie',
                    data: {
                        labels: ['ccTLDs', 'Regional SLDs', 'gTLDs', 'Webmails', 'Temporary', 'Custom', 'Invalid'],
                        datasets: [{
                            data: [ccTldCount, regionalSldCount, gTldCount, webmailCount, tempCount, customCount, invalidCount],
                            backgroundColor: isHighContrast ? [
                                '#00cc00', '#ffeb3b', '#00bcd4', '#ab47bc', '#d32f2f', '#757575', '#212121'
                            ] : [
                                '#28a745', '#ffc107', '#17a2b8', '#6f42c1', '#dc3545', '#6c757d', '#343a40'
                            ],
                            borderColor: isHighContrast ? '#fff' : '#000',
                            borderWidth: 1
                        }]
                    },
                    options: {
                        responsive: true,
                        plugins: {
                            legend: { position: 'bottom', labels: { font: { size: 12 } } },
                            title: { display: true, text: 'Email Domain Distribution', font: { size: 16 } }
                        },
                        animation: { duration: 500 }
                    }
                });
            }

            function lazyRenderCards(domainGroups, temporaryGroup, customWebmails, invalidEmails, delimiter) {
                const groups = [];
                if (temporaryGroup.emails.length > 0) groups.push(temporaryGroup);
                if (customWebmails.emails.length > 0) groups.push(customWebmails);
                if (invalidEmails.emails.length > 0) groups.push(invalidEmails);
                for (const [, info] of domainGroups) {
                    groups.push(info);
                }

                const observer = new IntersectionObserver((entries) => {
                    entries.forEach(entry => {
                        if (entry.isIntersecting) {
                            const info = JSON.parse(entry.target.dataset.info);
                            appendDomainCard(info, delimiter);
                            observer.unobserve(entry.target);
                        }
                    });
                }, { rootMargin: '100px' });

                const filterCategories = new Set($(".filter-category:checked").map(function() { return $(this).val(); }).get());
                const searchTerm = $("#searchDomains").val().toLowerCase();

                groups.sort((a, b) => {
                    const sortBy = $("#sortBy").val();
                    const sortDesc = $("#sortDesc").hasClass('active');
                    if (sortBy === 'name') {
                        return sortDesc ? b.displayName.localeCompare(a.displayName) : a.displayName.localeCompare(b.displayName);
                    } else if (sortBy === 'count') {
                        return sortDesc ? b.emails.length - a.emails.length : a.emails.length - b.emails.length;
                    } else {
                        const categoryOrder = ['webmail', 'ccTLD', 'regional-sld', 'gTLD', 'temporary', 'custom', 'invalid'];
                        const aIndex = categoryOrder.indexOf(a.tldInfo.type);
                        const bIndex = categoryOrder.indexOf(b.tldInfo.type);
                        return sortDesc ? bIndex - aIndex : aIndex - bIndex;
                    }
                }).forEach(info => {
                    if (filterCategories.has(info.tldInfo.type) && info.displayName.toLowerCase().includes(searchTerm)) {
                        const placeholder = document.createElement('div');
                        placeholder.className = 'col-md-4 domain-card-container mb-4';
                        placeholder.dataset.info = JSON.stringify(info);
                        $("#domainResults").append(placeholder);
                        observer.observe(placeholder);
                    }
                });
            }

            function appendDomainCard(info, delimiter) {
                const badgeClass = info.tldInfo.type === 'ccTLD' || info.tldInfo.type === 'ccTLD-idn' ? 'badge-ccTLD' :
                                 info.tldInfo.type === 'regional-sld' ? 'badge-regional-sld' :
                                 info.tldInfo.type === 'gTLD' ? 'badge-gTLD' :
                                 info.tldInfo.type === 'webmail' ? 'badge-webmail' :
                                 info.tldInfo.type === 'temporary' ? 'badge-temporary' :
                                 info.tldInfo.type === 'custom' ? 'badge-custom' :
                                 'badge-invalid';
                const cardHtml = `
                    <div class="col-md-4 domain-card-container mb-4" data-category="${info.tldInfo.type}" data-name="${info.displayName.toLowerCase()}">
                        <div class="domain-card">
                            <div class="domain-card-header">
                                <span>
                                    <i class="fas fa-globe"></i> ${info.displayName}
                                    <span class="badge ${badgeClass} ms-2">
                                        ${info.tldInfo.type.toUpperCase()}
                                        <span class="tooltip-content">${info.tldInfo.tooltip}</span>
                                    </span>
                                </span>
                                <div class="domain-card-header-actions">
                                    <span class="badge">${info.emails.length}</span>
                                    <button class="btn btn-sm copy-domain-emails" title="Copy Emails">
                                        <i class="fas fa-copy"></i>
                                    </button>
                                    <button class="btn btn-sm download-domain-emails" title="Download Emails">
                                        <i class="fas fa-download"></i>
                                    </button>
                                    <button class="btn btn-sm reset-domain-card" title="Close">
                                        <i class="fas fa-times text-danger"></i>
                                    </button>
                                </div>
                            </div>
                            <div class="p-3">
                                <textarea class="form-control domain-emails" rows="5" readonly aria-label="Emails for ${info.displayName}">${info.emails.join(delimiter)}</textarea>
                                <button class="btn btn-sm copy-textarea mt-2" style="background-color: #fff; color: var(--primary);" title="Copy Emails"><i class="fas fa-copy"></i> Copy</button>
                            </div>
                        </div>
                    </div>
                `;
                $("#domainResults").append(cardHtml);
            }

            let searchTimeout;
            $(".filter-category, #searchDomains, #filterSld").on("input change", function() {
                clearTimeout(searchTimeout);
                searchTimeout = setTimeout(() => $("#btnSeparate").trigger('click'), 300);
            });

            $("#sortBy").on("change", function() {
                $("#btnSeparate").trigger('click');
            });

            $("#sortAsc, #sortDesc").on("click", function() {
                $("#sortAsc, #sortDesc").removeClass('active');
                $(this).addClass('active');
                $("#btnSeparate").trigger('click');
            });

            $("#btnCopyAll").on("click", function () {
                const delimiter = $("#emailDelimiter").val() === "other" ? $("#customDelimiter").val() || "\n" : ($("#emailDelimiter").val() === "\\n" ? "\n" : $("#emailDelimiter").val());
                const emails = $(".domain-emails").map(function() { return $(this).val().trim(); }).get().join(delimiter);
                navigator.clipboard.writeText(emails);
                toastr.info("All emails copied to clipboard!");
            });

            $("#btnDownloadTxt").on("click", function () {
                const delimiter = $("#emailDelimiter").val() === "other" ? $("#customDelimiter").val() || "\n" : ($("#emailDelimiter").val() === "\\n" ? "\n" : $("#emailDelimiter").val());
                const emails = $(".domain-emails").map(function() { return $(this).val().trim(); }).get().join(delimiter);
                const blob = new Blob([emails], { type: "text/plain" });
                const url = URL.createObjectURL(blob);
                const a = document.createElement("a");
                a.href = url;
                a.download = "all-domain-emails.txt";
                a.click();
                URL.revokeObjectURL(url);
                toastr.success("All emails downloaded as TXT!");
            });

            $("#btnDownloadCsv").on("click", function () {
                const delimiter = $("#emailDelimiter").val() === "other" ? $("#customDelimiter").val() || "," : ($("#emailDelimiter").val() === "\\n" ? "," : $("#emailDelimiter").val());
                let csvContent = "Category,Domain,Emails\n";
                $(".domain-emails").each(function() {
                    const displayName = $(this).closest('.domain-card').find('.domain-card-header span').text();
                    const type = $(this).closest('.domain-card').find('.badge').text().split(' ')[0];
                    const emails = $(this).val().trim().split('\n').map(e => `"${e.replace(/"/g, '""')}"`).join(delimiter);
                    csvContent += `"${type}","${displayName.replace(/"/g, '""')}","${emails}"\n`;
                });
                const blob = new Blob([csvContent], { type: "text/csv" });
                const url = URL.createObjectURL(blob);
                const a = document.createElement("a");
                a.href = url;
                a.download = "all-domain-emails.csv";
                a.click();
                URL.revokeObjectURL(url);
                toastr.success("All emails downloaded as CSV!");
            });

            $("#btnDownloadJson").on("click", function() {
                const data = {};
                $(".domain-emails").each(function() {
                    const displayName = $(this).closest('.domain-card').find('.domain-card-header span').text();
                    const type = $(this).closest('.domain-card').find('.badge').text().split(' ')[0];
                    data[displayName] = {
                        category: type,
                        emails: $(this).val().trim().split('\n').filter(e => e)
                    };
                });
                const blob = new Blob([JSON.stringify(data, null, 2)], { type: "application/json" });
                const url = URL.createObjectURL(blob);
                const a = document.createElement("a");
                a.href = url;
                a.download = "all-domain-emails.json";
                a.click();
                URL.revokeObjectURL(url);
                toastr.success("All emails downloaded as JSON!");
            });

            $(document).on('click', '.copy-domain-emails, .copy-textarea', function() {
                const $textarea = $(this).closest('.domain-card').find('.domain-emails');
                navigator.clipboard.writeText($textarea.val().trim());
                toastr.info("Domain emails copied to clipboard!");
            });

            $(document).on('click', '.download-domain-emails', function() {
                const $card = $(this).closest('.domain-card');
                const $textarea = $card.find('.domain-emails');
                const domain = $card.find('.domain-card-header span').text().replace(/[^a-zA-Z0-9.-]/g, '');
                const emails = $textarea.val().trim();
                const blob = new Blob([emails], { type: "text/plain" });
                const url = URL.createObjectURL(blob);
                const a = document.createElement("a");
                a.href = url;
                a.download = `${domain}-emails.txt`;
                a.click();
                URL.revokeObjectURL(url);
                toastr.success(`${domain} emails downloaded!`);
            });

            $(document).on('click', '.reset-domain-card', function() {
                const $container = $(this).closest('.domain-card-container');
                $container.remove();
                updateTotalEmailCount();
                $("#btnSeparate").trigger('click');
            });

            $("#btnReset").on("click", function() {
                $("#domainResults").empty();
                $("#emailCount").text(0);
                $("#duplicateCount").text(0);
                $("#emailInput").val('');
                $("#filterSld").val('');
                $("#searchDomains").val('');
                $("#spf-input").val('');
                $("#dkim-input").val('');
                $("#statsCcTLD, #statsRegionalSld, #statsWebmail, #statsTemporary").text(0);
                if (chartInstance) {
                    chartInstance.destroy();
                    chartInstance = null;
                }
            });

            function updateTotalEmailCount() {
                const totalEmails = $(".domain-emails").toArray().reduce((sum, textarea) => 
                    sum + $(textarea).val().trim().split('\n').filter(e => e).length, 0);
                $("#emailCount").text(totalEmails);
            }

            function validateSPF() {
                const spfRecord = $("#spf-input").val().trim();
                const resultDiv = $("#spf-result");
                if (!spfRecord) {
                    resultDiv.text("❌ Please enter an SPF record").addClass("invalid-bg").removeClass("valid-bg warning-bg");
                    return;
                }
                if (!spfRecord.startsWith("v=spf1")) {
                    resultDiv.text("❌ Missing 'v=spf1' in SPF record").addClass("invalid-bg").removeClass("valid-bg warning-bg");
                    return;
                }
                if (spfRecord.includes("+all")) {
                    resultDiv.text("⚠️ Warning: '+all' allows all senders (risky!)").addClass("warning-bg").removeClass("valid-bg invalid-bg");
                    return;
                }
                if (!spfRecord.match(/[~+-]all$/)) {
                    resultDiv.text("⚠️ Warning: SPF record should end with ~all, -all, or +all").addClass("warning-bg").removeClass("valid-bg invalid-bg");
                    return;
                }
                resultDiv.text("✅ SPF syntax looks valid").addClass("valid-bg").removeClass("warning-bg invalid-bg");
            }

            function validateDKIM() {
                const dkimRecord = $("#dkim-input").val().trim();
                const resultDiv = $("#dkim-result");
                if (!dkimRecord) {
                    resultDiv.text("❌ Please enter a DKIM record").addClass("invalid-bg").removeClass("valid-bg warning-bg");
                    return;
                }
                if (!dkimRecord.startsWith("v=DKIM1")) {
                    resultDiv.text("❌ Missing 'v=DKIM1' in DKIM record").addClass("invalid-bg").removeClass("valid-bg warning-bg");
                    return;
                }
                if (!dkimRecord.includes("p=")) {
                    resultDiv.text("❌ Missing public key (p=) in DKIM record").addClass("invalid-bg").removeClass("valid-bg warning-bg");
                    return;
                }
                resultDiv.text("✅ DKIM syntax looks valid").addClass("valid-bg").removeClass("warning-bg invalid-bg");
            }
        });
    </script>
</body>
</html>

Comments

Popular posts from this blog

single email verifier

Email Extractor