Filter of Disposable Emails in PHPsteemCreated with Sketch.

in #coding2 months ago

If your website has user registration, a contact form, or a newsletter subscription, sooner or later you will run into trash email addresses. These are all those “disposable” inboxes from temporary services like guerrillamail.com, tempmail.com, mailinator.com, and so on. A user seems to leave an email, but it’s practically useless because you can’t contact this person — no email will be delivered to them. And if you don’t filter this kind of thing, your user database turns into a garbage dump.


This image was generated with Gemini.

Many people make a mistake, because they think that if filter_var($email, FILTER_VALIDATE_EMAIL) returns true, everything is fine. Not even close. That only checks the syntax. Meaning if there’s an “@” sign and the domain looks valid — PHP will say “Looks good!”. But in reality, the mailbox might not accept emails at all. Or the domain might be disposable and created purely to farm registrations.

That’s why I made a small anti-trash email filter in PHP, works on version 7. No libraries, no database, no external dependencies. It uses checkdnsrr(), proper validation, and a small text file with a blacklist of domains. Simple and clear.

What exactly we check

1. The email format is valid
Yes, nobody is canceling filter_var. It’s needed.

2. Whether this domain accepts emails (MX record check)
This already makes validation much more interesting. There are far fewer domains with MX records than domain names in general. And if there’s no MX, then in 99% of cases the email is fake.

3. Whether the domain is in the disposable email list
We add a text file blocked_domains.txt where we load a blacklist of domains. It’s easy to update manually. You can build your own list or find a ready-made list of temporary domains online.

The HTML form sends the specified email via POST. The handler script reads blocked_domains.txt, checks the format using filter_var(). If the format is valid, it extracts the domain, compares it with the blacklist (exact matches and suffixes), and checks DNS (MX/A/AAAA or resolve). It returns a status: bad, blocked, warn, or ok, and displays it under the form.

Storing domains blacklist in a .txt file is simply more convenient — you can update the list without redeploying the code, just upload a new file via FTP. No need to touch the code at all.

Where to use such a filter

Everywhere! For example:

  • Registration form
  • Newsletter subscription
  • Password recovery
  • Contact form on the website

Especially useful if you have a small project and you don’t want to fill your database with crap. Even if you don’t use email activation, this filter still cleans your traffic.

But don’t overdo it! The main rule of anti-spam: don’t overdo it, otherwise you’ll make things worse. We’re not building a fortress, we just don’t want to collect trash. So we only filter out obvious garbage — temporary domains and addresses without MX records. That’s it. This is just a simple check that saves time and database space.

Full code:

<?php
// ENABLE ERRORS (for testing)
error_reporting(E_ALL);
ini_set('display_errors', 1);

// Load blocked domains list from file
$blockedFile = __DIR__ . '/blocked_domains.txt';
$blocked = [];

if (file_exists($blockedFile)) {
    $blocked = array_filter(array_map('trim', file($blockedFile)));
    $blocked = array_map('strtolower', $blocked);
}

// Get email
$emailRaw = isset($_POST['email']) ? $_POST['email'] : '';
$email = trim($emailRaw);

// ===== FUNCTIONS =====
function isValidEmailFormat($email) {
    return filter_var($email, FILTER_VALIDATE_EMAIL);
}

function domainFromEmail($email) {
    $pos = strrpos($email, '@');
    return $pos === false ? '' : substr($email, $pos + 1);
}

function domainHasMx($domain) {
    if ($domain === '') return false;
    if (checkdnsrr($domain, 'MX')) return true;
    if (checkdnsrr($domain, 'A') || checkdnsrr($domain, 'AAAA')) return true;
    $ips = @gethostbynamel($domain);
    return !empty($ips);
}

function isBlockedDomain($domain, $blockedList) {
    $domain = strtolower($domain);
    if (in_array($domain, $blockedList)) return true;
    foreach ($blockedList as $bad) {
        if ($bad !== '' && substr($domain, -strlen($bad)) === $bad) {
            return true;
        }
    }
    return false;
}

function esc($s) {
    return htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}

// ===== PROCESSING =====
$result = null;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if ($email === '') {
        $result = ['status' => 'error', 'text' => 'Enter email'];
    } elseif (!isValidEmailFormat($email)) {
        $result = ['status' => 'bad', 'text' => '❌ Invalid email format'];
    } else {
        $domain = domainFromEmail($email);
        if (isBlockedDomain($domain, $blocked)) {
            $result = ['status' => 'blocked', 'text' => '⛔ Temporary/disposable mail is prohibited'];
        } elseif (!domainHasMx($domain)) {
            $result = ['status' => 'warn', 'text' => '⚠️ Domain does not accept mail (no MX/A records)'];
        } else {
            $result = ['status' => 'ok', 'text' => '✅ Email looks real'];
        }
    }
}
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Email Check</title>
<style>
    body{font-family:system-ui,Segoe UI,Roboto,Arial;margin:20px;background:#f7f7fb;}
    .box{max-width:680px;margin:auto;background:white;padding:20px;border-radius:8px;
         box-shadow:0 6px 20px rgba(0,0,0,.06);}
    input[type=email]{width:95%;padding:10px;font-size:15px;border:1px solid #ccc;border-radius:6px;}
    button{margin-top:10px;padding:10px 14px;border:0;background:#007bff;color:white;
           border-radius:6px;cursor:pointer;}
    .res{margin-top:12px;padding:10px;border-radius:6px;}
    .ok{background:#e6f9ee;border:1px solid #9be6b0;color:#1b6b2e;}
    .warn{background:#fff7e6;border:1px solid #ffd78f;color:#7b5b00;}
    .bad,.blocked{background:#ffecec;border:1px solid #ffb3b3;color:#8b1b1b;}
</style>
</head>
<body>
<div class="box">
    <h2>Email Check</h2>
    <form method="post">
        <input type="email" name="email" placeholder="Enter email" value="<?php echo esc($emailRaw); ?>" required>
        <button type="submit">Check</button>
    </form>

    <?php if ($result): ?>
        <?php
            switch ($result['status']) {
                case 'ok': $cls = 'ok'; break;
                case 'warn': $cls = 'warn'; break;
                case 'bad': $cls = 'bad'; break;
                case 'blocked': $cls = 'blocked'; break;
                default: $cls = 'bad';
            }
        ?>
        <div class="res <?php echo $cls; ?>"><?php echo esc($result['text']); ?></div>
    <?php endif; ?>

    <p><small>The list of blocked domains is loaded from the file <b>blocked_domains.txt</b>.</small></p>
</div>
</body>
</html>