Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Changelog
154 changes: 153 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,154 @@
# laravel-active-email
Disposable email address validator rule for Laravel apps

## Table of Contents

- [Overview](#overview)
- [Key Features](#key-features)
- [Installation](#installation)
- [Requirements](#requirements)
- [Install the Package](#install-the-package)
- [Publish the Config](#publish-the-config)
- [Usage](#usage)
- [Validator Approach](#validator-approach)
- [Class Approach](#class-approach)
- [Customization](#customization)
- [Strict Mode](#strict-mode)
- [Black List](#black-list)
- [Grey List](#grey-list)
- [White List](#white-list)
- [Testing](#testing)
- [To do](#to-do)
- [Security](#security)
- [Contribution](#contribution)
- [Changelog](#changelog)
- [Upgrading](#upgrading)
- [License](#license)

## Overview

This package provides a library of disposable domains and adds a validator to Laravel apps to check that a given email address isn't coming from a disposable email service such as `Mailinator`, `Guerillamail`, `Fastmail` considering all their possible wildcards.

### Key Features

- You can add your own preferred domains to the [black list](#black-list).
- You can [white list](#white-list) a domain to bye pass the blacklist. This can be useful in development environment.
- With [strict mode](#strict-mode), you can control the strictness of the validator, thereby allowing or preventing domains that are not necessarily disposable, but have been classified as disposable.
- Case-aware.
- Wildcard-aware.

## Installation


### Requirements

The package has been developed and tested to work with the following minimum requirements:

- PHP 8.x
- Laravel 10.x, 11.x

### Install the Package

You can install the package via Composer. The service provider is discovered automatically.

```bash
composer require veeqtoh/laravel-active-email
```

### Publish the Config

You can then publish the package's config file and update it as you'd prefer:
```bash
php artisan vendor:publish --provider="Veeqtoh\ActiveEmail\Providers\ActiveEmailProvider"
```

## Usage

### Validator Approach

Add the `notblacklisted` validator to your email validation rules array (or string) to ensure that the domain for a given email address is not blacklisted. I'd recommend you add it after the email validator to make sure a valid email is passed through:
```php
'emailField' => 'email|notblacklisted',
```

or

```php
'emailField' => ['email', 'notblacklisted'],
```

### Class Approach

Instantiate the `NotBlackListedEmail` Class as part of your email validation rules array to ensure that the domain for a given email address is not blacklisted. Again, I'd recommend you add it after the email validator to make sure a valid email is passed through:

```php
use Veeqtoh\ActiveEmail\Rules\NotBlackListedEmail;

'emailField' => ['email', new NotBlackListedEmail()],
```

### Customization

The package is highly customizable from the config file with the following features:

#### Strict Mode

This value determines the strictness level of this feature. when set to `true`, domains in the [grey list](#grey-list) are also blacklisted.

It is turned on by default, but can be set in your .env file as follows:

```php
DISPOSABLE_EMAIL_STRICT_MODE=true,
```

#### Black List

This is a list of base domains with or without the TLD that are blacklisted by default. Add a domain to this list to blacklist it.

#### Grey List

This is a list of base domains with or without the TLD that aren't blacklisted by default except when in strict mode. Add a domain to this list to whitelist it when the feature is not set to strict mode. Ensure that the domain is not on the [black list](#black-list).

#### White List

This is a list of base domains with or without the TLD that are blacklisted by default but you want them to be bye passed.

## To Do

There's always something that can be done to improve this package. I'd keep updating this list as I think of them.

- Crawl the web to grab an updated list of disposable domains.
- Maybe setup a schedule for it..

## Testing

To run the package's unit tests, run the following command:

``` bash
vendor/bin/pest
```

## Security

If you find any security related issues, please contact me directly at [victorjohnukam@gmail.com](mailto:victorjohnukam@gmail.com) to report it.

## Contribution

If you wish to make any changes or improvements to the package, feel free to make a pull request.

Note: A contribution guide will be added soon.

## Changelog

Check the [CHANGELOG](CHANGELOG.md) to get more information about the latest changes.

## Upgrading

Check the [UPGRADE](UPGRADE.md) guide to get more information on how to update this library to newer versions.

## License

The MIT License (MIT). Please see [License File](LICENSE) for more information.

## Support Me

If you've found this package useful, please consider sponsoring this project. It will encourage me to keep maintaining it.
1 change: 1 addition & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Upgrade
34 changes: 24 additions & 10 deletions config/active-email.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,46 @@

/*
|--------------------------------------------------------------------------
| Blacklist
| Black List
|--------------------------------------------------------------------------
|
| This is a list of base domains without the TLD that are blacklisted by
| default. Add a domain to this list to blacklist it.
| This is a list of base domains with or without the TLD that are
| blacklisted by default. Add a domain to this list to blacklist it.
|
*/

'blacklist' => [
//
//
],

/*
|--------------------------------------------------------------------------
| Greylist
| Grey List
|--------------------------------------------------------------------------
|
| This is a list of base domains without the TLD that aren't blacklisted by
| default except when in strict mode. Add a domain to this list to whitelist
| it when the feature is not set to strict mode. Ensure that the domain is not
| on the blacklist above.
| This is a list of base domains with or without the TLD that aren't
| blacklisted by default except when in strict mode. Add a domain to this
| list to whitelist it when the feature is not set to strict mode.
| Ensure that the domain is not on the blacklist above.
|
*/

'greylist' => [
//
//
],

/*
|--------------------------------------------------------------------------
| White List
|--------------------------------------------------------------------------
|
| This is a list of base domains with or without the TLD that are
| blacklisted by default but you want them to be bye passed.
|
*/

'whitelist' => [
//
],

];
4 changes: 3 additions & 1 deletion src/DisposableEmail.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
*/
class DisposableEmail
{
/**
/**
* Retrieve a list of base domains without the TLDs that are blacklisted by default.
*
* @return array
*/
public function getBlacklist() : array
{
Expand Down
3 changes: 1 addition & 2 deletions src/Providers/ActiveEmailProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,10 @@ public function boot() : void
__DIR__ . '/../../config/active-email.php' => config_path('active-email.php'),
], 'config');

// Register the custom validation rule
// Register the custom validation rule.
Validator::extend('notblacklisted', function ($attribute, $value, $parameters, $validator) {
$rule = new NotBlacklistedEmail();

// Create a Closure for the fail method
$fail = function($message) use ($attribute, $validator) {
$validator->errors()->add($attribute, $message);
};
Expand Down
20 changes: 13 additions & 7 deletions src/Rules/NotBlacklistedEmail.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ public function __construct()

/**
* Run the validation rule.
*
*
* @param string $attribute The name of the attribute being validated.
* @param mixed $value The value of the attribute being validated.
* @param \Closure(mixed): \Illuminate\Translation\PotentiallyTranslatedString $fail
* @param \Closure(mixed): \Illuminate\Translation\PotentiallyTranslatedString $fail
* The callback that should be used to report validation failures.
*
*
* @return void
*/
public function validate(string $attribute, mixed $value, Closure $fail) : void
Expand All @@ -41,11 +41,17 @@ public function validate(string $attribute, mixed $value, Closure $fail) : void
$domain = $this->getDomainName('@', $value, 1);
$domainName = $this->getDomainName('.', $domain, 0);

$mergedBlackLists = array_merge(config('active-email.blacklist'), $disposableEmail->getBlacklist());
$blackListedDomainNames = array_unique($mergedBlackLists);
$blackListedDomainNames = array_unique(array_merge(config('active-email.blacklist'), $disposableEmail->getBlacklist()));
$greyListedDomainNames = array_unique(array_merge(config('active-email.greylist'), $disposableEmail->getGreyList()));
$whiteListedDomainNames = array_unique(config('active-email.whitelist'));

foreach ($whiteListedDomainNames as $whiteListedDomainName) {
$byePass = $this->getDomainName('.', $whiteListedDomainName, 0);

$mergedGreyLists = array_merge(config('active-email.greylist'), $disposableEmail->getGreyList());
$greyListedDomainNames = array_unique($mergedGreyLists);
if ($domainName === $byePass) {
return;
}
}

if (config('active-email.strict_mode')) {
$blackListedDomainNames = array_merge($blackListedDomainNames, $greyListedDomainNames);
Expand Down
64 changes: 64 additions & 0 deletions tests/Unit/ActiveEmailTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,67 @@
expect($validator->fails())->toBeTrue();
}
});

it('validates that domains can be whitelisted - class instantiation', function () {
$rule = ['email' => [new NotBlacklistedEmail]];

// Valid email addresses (not blacklisted).
$validEmails = [
'user@gmail.com',
'user@yahoo.com',
'user@customdomain.org',
'user@10minutemail.com',
];

foreach ($validEmails as $email) {
$validator = Validator::make(['email' => $email], $rule);
expect($validator->passes())->toBeTrue();
}

// Invalid email addresses (blacklisted domains).
$invalidEmails = [
'user@mailinator.com',
'user@tempmail.com',
'user@example.ltd',
'user@example.co',
'user@example.com.nh',
'user@example.co.uk',
];

foreach ($invalidEmails as $email) {
$validator = Validator::make(['email' => $email], $rule);
expect($validator->fails())->toBeTrue();
}
});

it('validates that domains can be whitelisted - alias', function () {
$rule = ['email' => 'notblacklisted'];

// Valid email addresses (not blacklisted).
$validEmails = [
'user@gmail.com',
'user@yahoo.com',
'user@customdomain.org',
'user@10minutemail.com',
];

foreach ($validEmails as $email) {
$validator = Validator::make(['email' => $email], $rule);
expect($validator->passes())->toBeTrue();
}

// Invalid email addresses (blacklisted domains).
$invalidEmails = [
'user@mailinator.com',
'user@tempmail.com',
'user@example.ltd',
'user@example.co',
'user@example.com.nh',
'user@example.co.uk',
];

foreach ($invalidEmails as $email) {
$validator = Validator::make(['email' => $email], $rule);
expect($validator->fails())->toBeTrue();
}
});
3 changes: 2 additions & 1 deletion tests/Unit/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ protected function getPackageAliases($app)
protected function getEnvironmentSetUp($app)
{
// Set up any necessary configurations here
$app['config']->set('active-email.blacklist', ['mailinator.com', 'tempmail.com', 'example.ltd', 'example.co', 'example.com.nh', 'example.co.uk']);
$app['config']->set('active-email.blacklist', ['mailinator.com', 'tempmail.com', 'example.ltd', 'example.co', 'example.com.nh', 'example.co.uk', '10minutemail']);
$app['config']->set('active-email.greylist', []);
$app['config']->set('active-email.whitelist', ['10minutemail']);
$app['config']->set('active-email.strict_mode', false);
}
}