webo3/smtp-email-validation

Comprehensive email validation: syntax, disposable domain detection, DNS checks, and SMTP verification with scoring.

Installs: 6

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 1

Forks: 0

Open Issues: 0

pkg:composer/webo3/smtp-email-validation

v2.0.0 2026-02-08 01:15 UTC

This package is auto-updated.

Last update: 2026-02-08 01:19:30 UTC


README

Comprehensive PHP email validation library with syntax checking, disposable domain detection, DNS verification, SMTP mailbox validation, and a scoring system.

Requires: PHP 8.0+ with fsockopen, getmxrr, dns_get_record and ability to connect to remote port 25.

Installation

composer require webo3/smtp-email-validation

Usage

Full Validation with Scoring (Recommended)

use webO3\SmtpEmailValidation\EmailValidator;

$validator = new EmailValidator(
    fromEmail: 'noreply@yourdomain.com',
    validThreshold: 60,  // Score >= 60 considered valid
    timeout: 30,
);

$result = $validator->validate('user@example.com');

echo $result->score;    // 0-100
echo $result->isValid;  // true/false
echo $result->email;    // 'user@example.com'

// Per-check breakdown
foreach ($result->checks as $check) {
    echo "{$check->name}: {$check->status->value} (score: {$check->score})\n";
}

// Get a specific check
$smtpCheck = $result->getCheck('smtp');

// Convert to array (useful for JSON APIs)
$array = $result->toArray();

Quick Static Method

use webO3\SmtpEmailValidation\Validator;

// Full validation with scoring
$result = Validator::validate('user@example.com', from: 'noreply@yourdomain.com');
echo $result->score; // 0-100

Custom Check Configuration

Run only specific checks or adjust settings:

use webO3\SmtpEmailValidation\EmailValidator;
use webO3\SmtpEmailValidation\Check\SyntaxCheck;
use webO3\SmtpEmailValidation\Check\DisposableDomainCheck;
use webO3\SmtpEmailValidation\Check\DnsCheck;

// Lightweight validation without SMTP (no port 25 needed)
$validator = new EmailValidator(
    validThreshold: 50,
    checks: [
        new SyntaxCheck(),
        new DisposableDomainCheck(cacheTtl: 3600), // refresh list every hour
        new DnsCheck(),
    ],
);

$result = $validator->validate('user@example.com');

Legacy SMTP-Only Check (Backward Compatible)

use webO3\SmtpEmailValidation\Validator;

$response = Validator::test('noreply@yourdomain.com', 'user@example.com');
// Returns: ['code' => 250, 'success' => true, 'msg' => 'Email is valid', 'debug' => [...]]

Examples

Runnable example scripts are provided in the examples/ directory:

# Full validation with score breakdown
php examples/basic-validation.php user@example.com

# Syntax-only check (no network calls)
php examples/syntax-only.php user@example.com

# Batch validation from arguments or file
php examples/batch-validation.php user1@gmail.com user2@mailinator.com
php examples/batch-validation.php --file emails.txt

# Custom checks (skip SMTP, JSON output)
php examples/custom-checks.php user@example.com

Validation Checks

The library runs four checks in sequence:

Check Weight Description
Syntax 25% RFC 5322 format validation (local-part length, domain structure, etc.)
Disposable 15% Checks against a regularly updated list of disposable email providers
DNS 25% MX records, A-record fallback, SPF and DMARC presence
SMTP 35% Connects to mail server and verifies the mailbox exists

If syntax validation fails, all subsequent checks are skipped and the score is 0.

Disposable Domain List

The disposable domain check automatically fetches the latest list from the disposable-email-domains community project and caches it locally (default: 24 hours). If the fetch fails, a bundled fallback list is used.

You can configure the cache TTL and location:

new DisposableDomainCheck(
    cachePath: '/path/to/cache.json',  // default: sys_get_temp_dir()
    cacheTtl: 3600,                    // refresh every hour (default: 86400)
);

Scoring System

Each check produces a score from 0-100, weighted by importance:

  • Overall score = weighted average of non-skipped checks (0-100)
  • isValid = score >= threshold (default: 60)

Example Scores

Scenario Score
Valid email, all checks pass 100
Valid email, disposable domain ~85
Valid email, SMTP greylisting (451/452) ~79
Valid email, SMTP rejected ~65
Invalid syntax 0

DNS Sub-Scoring

DNS Component Points
MX records found 40
A-record fallback (no MX) 20
SPF record present 30
DMARC record present 30

SMTP Sub-Scoring

SMTP Stage Points
Connected to MX server 20
Valid 220 greeting 20
RCPT TO accepted (250) 60
Greylisting (451/452) 40

Legacy Response Codes

When using Validator::test():

Code Success Description
10 false No MX records found for domain
15 false Could not connect to any MX servers
20 false Connection timeout
25 false Server did not return 220 greeting
250 true Email is valid
451/452 true Temporary rejection (greylisting)
Other false Email rejected

Testing

composer install
vendor/bin/phpunit

Warning

  • Many hosting providers and ISPs block direct connections to remote port 25.
  • Use a valid FROM address — some blacklists may block specific sender addresses.