PHPackages                             raul3k/disposable-email-blocker-core - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Mail &amp; Notifications](/categories/mail)
4. /
5. raul3k/disposable-email-blocker-core

ActiveLibrary[Mail &amp; Notifications](/categories/mail)

raul3k/disposable-email-blocker-core
====================================

Fast disposable/temporary email detection with PSL support, pattern matching, caching and whitelist

v1.1.0(4mo ago)1130[6 PRs](https://github.com/raul3k/disposable-email-blocker-core/pulls)1MITPHPPHP ^8.1CI passing

Since Feb 27Pushed 1w agoCompare

[ Source](https://github.com/raul3k/disposable-email-blocker-core)[ Packagist](https://packagist.org/packages/raul3k/disposable-email-blocker-core)[ Docs](https://github.com/raul3k/disposable-email-blocker-core)[ RSS](/packages/raul3k-disposable-email-blocker-core/feed)WikiDiscussions main Synced 3w ago

READMEChangelog (2)Dependencies (6)Versions (11)Used By (1)

Disposable Email Blocker - Core
===============================

[](#disposable-email-blocker---core)

Fast disposable/temporary email detection with full Public Suffix List (PSL) support, pattern matching, caching, and whitelist capabilities.

Table of Contents
-----------------

[](#table-of-contents)

- [Features](#features)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Builder](#builder)
- [Detailed Check Results](#detailed-check-results)
- [Batch Operations](#batch-operations)
- [Pattern-Based Detection](#pattern-based-detection)
- [Whitelist Support](#whitelist-support)
- [Caching](#caching)
- [Custom Checkers](#custom-checkers)
- [Working with Sources](#working-with-sources)
- [Updating the Public Suffix List](#updating-the-public-suffix-list)
- [Domain Info](#domain-info)
- [Domain Normalization](#domain-normalization)
- [Framework Integration](#framework-integration)
- [Development](#development)
- [License](#license)

Features
--------

[](#features)

- **Fast O(1) lookups** using hash-based domain checking
- **Full PSL support** - correctly handles subdomains and public suffixes
- **IDN/Punycode support** - international domain names are handled correctly
- **Pattern matching** - detect suspicious domain patterns via regex
- **Whitelist support** - allow specific domains to bypass checks
- **Caching layer** - PSR-6/PSR-16 compatible cache adapters
- **Detailed results** - `CheckResult` with matched checker info
- **Batch operations** - efficiently check multiple emails at once
- **Multiple checkers** - file-based, callback-based, or chain multiple checkers
- **Domain parsing** - `DomainInfo` for detailed domain analysis (PSL, subdomain, IDN)
- **Extensible sources** - built-in sources + custom parsers for any format
- **CLI tools** - `bin/update-domains` to fetch and merge domain lists, `bin/update-psl` to update the Public Suffix List
- **Framework agnostic** - use with any PHP project

Installation
------------

[](#installation)

```
composer require raul3k/disposable-email-blocker-core
```

Quick Start
-----------

[](#quick-start)

```
use Raul3k\DisposableBlocker\Core\DisposableEmailChecker;

$checker = DisposableEmailChecker::create();

// Check if email is disposable
$checker->isDisposable('test@mailinator.com'); // true
$checker->isDisposable('test@gmail.com');      // false

// Safe version (returns false for invalid emails instead of throwing)
$checker->isDisposableSafe('invalid-email');   // false

// Check domain directly
$checker->isDomainDisposable('tempmail.com');  // true
```

Builder
-------

[](#builder)

The fluent builder is the recommended way to compose checkers:

```
use Raul3k\DisposableBlocker\Core\DisposableEmailChecker;

$checker = DisposableEmailChecker::builder()
    ->withBundledDomains()
    ->withPatternDetection()
    ->withWhitelist(['mycompany.com', 'partner.org'])
    ->withFileCache('/tmp/disposable-cache')
    ->build();

$checker->isDisposable('test@mailinator.com'); // true
$checker->isDisposable('test@mycompany.com');  // false (whitelisted)
```

Available builder methods:

- `withBundledDomains()` - use the bundled ~159k domain list
- `withDomainsFile(string $path)` - use a custom domains file
- `withPatternDetection(?array $patterns = null)` - enable regex pattern matching
- `withChecker(CheckerInterface $checker)` - add any custom checker
- `withCallback(callable $callback)` - add a callback-based checker
- `withWhitelist(array $domains)` - whitelist specific domains
- `withFileCache(string $directory, ?int $ttl = 3600)` - enable file-based caching
- `withCache(CacheInterface $cache, ?int $ttl = 3600)` - use a custom cache
- `withNormalizer(DomainNormalizer $normalizer)` - use a custom normalizer

Detailed Check Results
----------------------

[](#detailed-check-results)

Get detailed information about the check result:

```
use Raul3k\DisposableBlocker\Core\DisposableEmailChecker;

$checker = DisposableEmailChecker::create();

// Check an email
$result = $checker->check('test@mailinator.com');

$result->isDisposable();      // true
$result->isSafe();            // false
$result->getDomain();         // 'mailinator.com'
$result->getOriginalInput();  // 'test@mailinator.com'
$result->getMatchedChecker(); // 'Raul3k\DisposableBlocker\Core\Checkers\FileChecker'
$result->isWhitelisted();     // false
$result->toArray();           // array representation
$result->toJson();            // JSON string

// Check a domain directly
$result = $checker->checkDomain('mailinator.com');
$result->isDisposable(); // true

// Safe versions (return safe result for invalid input instead of throwing)
$result = $checker->checkSafe('invalid-email');
$result->isSafe(); // true
```

Batch Operations
----------------

[](#batch-operations)

Check multiple emails efficiently:

```
use Raul3k\DisposableBlocker\Core\DisposableEmailChecker;

$checker = DisposableEmailChecker::create();

$emails = [
    'user1@gmail.com',
    'user2@mailinator.com',
    'user3@yahoo.com',
];

// Get boolean results
$results = $checker->isDisposableBatch($emails);
// ['user1@gmail.com' => false, 'user2@mailinator.com' => true, 'user3@yahoo.com' => false]

// Get detailed results
$results = $checker->checkBatch($emails);
// ['user1@gmail.com' => CheckResult, 'user2@mailinator.com' => CheckResult, ...]
```

Pattern-Based Detection
-----------------------

[](#pattern-based-detection)

Detect suspicious domain patterns using regex:

```
use Raul3k\DisposableBlocker\Core\DisposableEmailChecker;
use Raul3k\DisposableBlocker\Core\Checkers\{ChainChecker, FileChecker, PatternChecker};

// Combine file-based checking with pattern matching
$checker = DisposableEmailChecker::create(
    new ChainChecker([
        new FileChecker(__DIR__ . '/domains.txt'),
        new PatternChecker(), // Uses default patterns
    ])
);

// Default patterns detect:
// - temp*, disposable*, throwaway*, fake*, junk*, spam*
// - 10minutemail, 5minmail, etc.
// - guerrillamail, yopmail, mailinator
// - Suspicious TLDs: .tk, .ml, .ga, .cf, .gq

// Add custom patterns
$patternChecker = new PatternChecker();
$patternChecker->addPattern('/^suspicious-/i');
```

Whitelist Support
-----------------

[](#whitelist-support)

Allow specific domains to bypass disposable checks:

```
use Raul3k\DisposableBlocker\Core\DisposableEmailChecker;
use Raul3k\DisposableBlocker\Core\Checkers\{FileChecker, WhitelistChecker};

$innerChecker = new FileChecker(__DIR__ . '/domains.txt');
$whitelistChecker = new WhitelistChecker($innerChecker, [
    'company.com',      // Allow company.com and all subdomains
    'partner.org',
]);

$checker = DisposableEmailChecker::create($whitelistChecker);

// Even if mailinator.com is in the list, whitelist takes precedence
$whitelistChecker->addToWhitelist('special-case.mailinator.com');

// Check whitelist status
$whitelistChecker->isWhitelisted('company.com');     // true
$whitelistChecker->isWhitelisted('sub.company.com'); // true (parent is whitelisted)
```

Caching
-------

[](#caching)

Add caching to improve performance for repeated checks:

```
use Raul3k\DisposableBlocker\Core\DisposableEmailChecker;
use Raul3k\DisposableBlocker\Core\Checkers\{FileChecker, CachedChecker};
use Raul3k\DisposableBlocker\Core\Cache\{ArrayCache, FileCache};

// In-memory cache (single request)
$cache = new ArrayCache();

// File-based cache (persistent)
$cache = new FileCache('/path/to/cache/dir');

// Wrap any checker with caching
$innerChecker = new FileChecker(__DIR__ . '/domains.txt');
$cachedChecker = new CachedChecker($innerChecker, $cache, ttl: 3600);

$checker = DisposableEmailChecker::create($cachedChecker);
```

### PSR-6/PSR-16 Cache Adapters

[](#psr-6psr-16-cache-adapters)

Use any PSR-compatible cache:

```
use Raul3k\DisposableBlocker\Core\Cache\{Psr6Adapter, Psr16Adapter};

// PSR-16 (SimpleCache)
$cache = new Psr16Adapter($yourPsr16Cache);

// PSR-6 (CacheItemPool)
$cache = new Psr6Adapter($yourPsr6Pool);

$cachedChecker = new CachedChecker($innerChecker, $cache);
```

Custom Checkers
---------------

[](#custom-checkers)

### Using a Callback (Redis, Database, API, etc.)

[](#using-a-callback-redis-database-api-etc)

```
use Raul3k\DisposableBlocker\Core\DisposableEmailChecker;
use Raul3k\DisposableBlocker\Core\Checkers\CallbackChecker;

// Redis
$checker = DisposableEmailChecker::create(
    new CallbackChecker(fn(string $domain) => $redis->sismember('disposable_domains', $domain))
);

// PDO
$stmt = $pdo->prepare('SELECT 1 FROM disposable_domains WHERE domain = ? LIMIT 1');
$checker = DisposableEmailChecker::create(
    new CallbackChecker(function (string $domain) use ($stmt): bool {
        $stmt->execute([$domain]);
        return (bool) $stmt->fetchColumn();
    })
);

// Eloquent (Laravel)
$checker = DisposableEmailChecker::create(
    new CallbackChecker(fn(string $domain) => \App\Models\DisposableDomain::where('domain', $domain)->exists())
);
```

### Implementing CheckerInterface

[](#implementing-checkerinterface)

For reusable or complex checkers, implement the interface directly:

```
use Raul3k\DisposableBlocker\Core\Checkers\CheckerInterface;

class PdoDatabaseChecker implements CheckerInterface
{
    private \PDOStatement $stmt;

    public function __construct(\PDO $pdo, string $table = 'disposable_domains')
    {
        $this->stmt = $pdo->prepare(
            sprintf('SELECT 1 FROM %s WHERE domain = ? LIMIT 1', $table)
        );
    }

    public function isDomainDisposable(string $normalizedDomain): bool
    {
        $this->stmt->execute([$normalizedDomain]);
        return (bool) $this->stmt->fetchColumn();
    }
}

// Usage
$checker = DisposableEmailChecker::create(new PdoDatabaseChecker($pdo));
```

```
use Illuminate\Database\Eloquent\Model;
use Raul3k\DisposableBlocker\Core\Checkers\CheckerInterface;

class EloquentDatabaseChecker implements CheckerInterface
{
    /** @var class-string */
    private string $model;

    /** @param class-string $model */
    public function __construct(string $model = \App\Models\DisposableDomain::class)
    {
        $this->model = $model;
    }

    public function isDomainDisposable(string $normalizedDomain): bool
    {
        return $this->model::where('domain', $normalizedDomain)->exists();
    }
}

// Usage
$checker = DisposableEmailChecker::create(new EloquentDatabaseChecker());
```

### Using a Custom File

[](#using-a-custom-file)

```
use Raul3k\DisposableBlocker\Core\DisposableEmailChecker;
use Raul3k\DisposableBlocker\Core\Checkers\FileChecker;

$checker = DisposableEmailChecker::create(
    new FileChecker('/path/to/your/domains.txt')
);
```

### Chaining Multiple Checkers

[](#chaining-multiple-checkers)

```
use Raul3k\DisposableBlocker\Core\DisposableEmailChecker;
use Raul3k\DisposableBlocker\Core\Checkers\{ChainChecker, FileChecker, PatternChecker, CallbackChecker};

$checker = DisposableEmailChecker::create(
    new ChainChecker([
        new FileChecker('/path/to/domains.txt'),
        new PatternChecker(),
        new CallbackChecker(fn($domain) => $redis->sismember('extra_domains', $domain)),
    ])
);

// After checking, you can see which checker matched
$result = $checker->check('test@tempmail.com');
$result->getMatchedChecker(); // 'Raul3k\DisposableBlocker\Core\Checkers\PatternChecker'
```

Working with Sources
--------------------

[](#working-with-sources)

Sources provide lists of disposable domains. The library includes several pre-configured sources.

### Available Built-in Sources

[](#available-built-in-sources)

SourceFormatSize`disposable-email-domains`Text~5k`burner-email-providers`Text~27k`mailchecker`Text~56k`ivolo-disposable`JSON~122k`fakefilter`Text~10k### Fetching from Sources

[](#fetching-from-sources)

```
use Raul3k\DisposableBlocker\Core\Sources\SourceRegistry;

$registry = new SourceRegistry();

// List available sources
$sources = $registry->list();
// ['disposable-email-domains', 'burner-email-providers', 'mailchecker', ...]

// Fetch domains from a source
$source = $registry->get('disposable-email-domains');
foreach ($source->fetch() as $domain) {
    echo $domain . "\n";
}
```

### Adding Custom Sources

[](#adding-custom-sources)

```
use Raul3k\DisposableBlocker\Core\Sources\{SourceRegistry, UrlSource, FileSource};
use Raul3k\DisposableBlocker\Core\Parsers\{TextLineParser, JsonArrayParser};

$registry = new SourceRegistry();

// Remote text file (one domain per line)
$registry->register(new UrlSource(
    url: 'https://example.com/domains.txt',
    name: 'my-text-source',
    parser: new TextLineParser()
));

// Remote JSON array
$registry->register(new UrlSource(
    url: 'https://example.com/domains.json',
    name: 'my-json-source',
    parser: new JsonArrayParser()
));

// JSON with nested path
$registry->register(new UrlSource(
    url: 'https://api.example.com/data.json',
    name: 'my-nested-json',
    parser: new JsonArrayParser('response.data.domains')
));

// Local file
$registry->register(new FileSource(
    path: '/path/to/local-domains.txt',
    name: 'my-local-source'
));
```

### Updating the Bundled Domain List

[](#updating-the-bundled-domain-list)

Use the CLI tool to fetch domains from all sources and update the bundled list:

```
# Update from all sources
./bin/update-domains

# Preview without writing
./bin/update-domains --dry-run

# Fetch from specific sources only
./bin/update-domains --source=disposable-email-domains --source=mailchecker

# Custom output path
./bin/update-domains --output=storage/domains.txt

# Show detailed progress
./bin/update-domains --verbose

# See all options
./bin/update-domains --help
```

You can customize sources via a `disposable-blocker.php` config file in your project root:

```
