├── .github
└── FUNDING.yml
├── .gitignore
├── .styleci.yml
├── .travis.yml
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── composer.json
├── config
└── mailbox-layer.php
├── docs
└── images
│ └── check-image.png
├── phpstan.neon
├── phpunit.xml
├── src
├── Classes
│ ├── MailboxLayer.php
│ └── ValidationResult.php
├── Exceptions
│ └── MailboxLayerException.php
├── Facades
│ └── MailboxLayer.php
└── Providers
│ └── MailboxLayerProvider.php
└── tests
└── Unit
├── Classes
├── MailboxLayer
│ ├── CheckManyTest.php
│ └── CheckTest.php
└── ValidationResult
│ └── MakeFromResponseTest.php
└── TestCase.php
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: ash-jc-allen
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | vendor/
3 | composer.lock
4 | .phpunit.result.cache
--------------------------------------------------------------------------------
/.styleci.yml:
--------------------------------------------------------------------------------
1 | preset: laravel
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | cache:
4 | directories:
5 | - $HOME/.composer/cache
6 |
7 | matrix:
8 | fast_finish: true
9 | include:
10 | # Laravel 7.*
11 | - php: 7.3
12 | env: LARAVEL='7.*'
13 | - php: 7.4
14 | env: LARAVEL='7.*'
15 | - php: 8.0
16 | env: LARAVEL='7.*'
17 | # Laravel 8.*
18 | - php: 7.3
19 | env: LARAVEL='8.*'
20 | - php: 7.4
21 | env: LARAVEL='8.*'
22 | - php: 8.0
23 | env: LARAVEL='8.*'
24 |
25 | before_install:
26 | - travis_retry composer self-update
27 | - travis_retry composer require --no-update --no-interaction "illuminate/container:${LARAVEL}" "illuminate/cache:${LARAVEL}"
28 |
29 | install:
30 | - travis_retry composer update --prefer-dist --no-interaction --no-suggest
31 | - travis_retry composer du -o
32 |
33 | before_script:
34 | - phpenv config-rm xdebug.ini || return 0
35 |
36 | script:
37 | - vendor/bin/phpunit
38 | - vendor/bin/phpstan analyze src config --level max
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | **1.0.1 (released 2020-12-31):**
4 | - Added the package logo to the documentation.
5 |
6 | **1.0.0 (released 2020-12-16):**
7 | - Improved code quality.
8 | - Added documentation.
9 | - Added unit tests.
10 | - Configured tests and phpstan to run on Travis CI.
11 |
12 | **0.1.0 (pre-release):**
13 | - Initial work.
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Ashley Allen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | ## Table of Contents
14 |
15 | - [Overview](#overview)
16 | - [Installation](#installation)
17 | - [Requirements](#requirements)
18 | - [Install the Package](#install-the-package)
19 | - [Publish the Config](#publish-the-config)
20 | - [Getting Your Mailbox Layer API Key](#getting-your-mailbox-layer-api-key)
21 | - [Usage](#usage)
22 | - [Methods](#methods)
23 | - [Validating One Email Address](#validating-one-email-address)
24 | - [Validating Multiple Email Addresses](#validating-multiple-email-addresses)
25 | - [Facade](#facade)
26 | - [Available Validation Result Properties](#available-validation-result-properties)
27 | - [Caching](#caching)
28 | - [Caching Validation Results](#caching-validation-results)
29 | - [Busting the Cached Validation Results](#busting-the-cached-validation-results)
30 | - [Options](#options)
31 | - [Using HTTPS](#using-https)
32 | - [Running an SMTP Check](#running-an-smtp-check)
33 | - [Testing](#testing)
34 | - [Security](#security)
35 | - [Contribution](#contribution)
36 | - [Credits](#credits)
37 | - [Changelog](#changelog)
38 | - [License](#license)
39 |
40 | ## Overview
41 | Laravel Mailbox Layer is a lightweight wrapper Laravel package that can be used for validating email addresses via the
42 | [Mailbox Layer API](https://mailboxlayer.com/). The package supports caching so that you can start validating email addresses instantly.
43 |
44 | 
45 |
46 | ## Installation
47 |
48 | ### Requirements
49 | The package has been developed and tested to work with the following minimum requirements:
50 |
51 | - PHP 7.3
52 | - Laravel 7
53 |
54 | ### Install the Package
55 | You can install the package via Composer:
56 |
57 | ```bash
58 | composer require ashallendesign/laravel-mailboxlayer
59 | ```
60 |
61 | ### Publish the Config
62 | You can then publish the package's config file (so that you can make changes to them) by using the following command:
63 | ```bash
64 | php artisan vendor:publish --provider="AshAllenDesign\MailboxLayer\Providers\MailboxLayerProvider"
65 | ```
66 |
67 | ### Getting Your Mailbox Layer API Key
68 | To use this package and interact with the Mailbox Layer API, you'll need to register on the [Mailbox Layer API](https://mailboxlayer.com/)
69 | website and get your API key. Once you have the key, you can set it in your ` .env ` file as shown below:
70 |
71 | ```
72 | MAILBOX_LAYER_API_KEY=your-api-key-here
73 | ```
74 |
75 | ## Usage
76 | ### Methods
77 | #### Validating One Email Address
78 |
79 | To validate a single email address, you can use the ` check() ` method that is provided in the package. This method returns a ` ValidationResult ` object.
80 |
81 | The example below shows how to validate a single email address:
82 |
83 | ```php
84 | use AshAllenDesign\MailboxLayer\Classes\MailboxLayer;
85 |
86 | $mailboxLayer = new MailboxLayer('api-key-here');
87 | $validationResult = $mailboxLayer->check('example@domain.com');
88 | ```
89 |
90 | #### Validating Multiple Email Addresses
91 |
92 | To validate multiple email addresses, you can use the ` checkMany() ` method that is provided in the package. This method returns a ` Collection ` of ` ValidationResult ` objects.
93 |
94 | The example below shows how to validate multiple email addresses:
95 |
96 | ```php
97 | use AshAllenDesign\MailboxLayer\Classes\MailboxLayer;
98 |
99 | $mailboxLayer = new MailboxLayer('api-key-here');
100 | $validationResults = $mailboxLayer->checkMany(['example@domain.com', 'test@test.com']);
101 | ```
102 |
103 |
104 | ### Facade
105 | If you prefer to use facades in Laravel, you can choose to use the provided ` Mailbox Layer ` facade instead of instantiating the ``` AshAllenDesign\MailboxLayer\Classes\MailboxLayer ```
106 | class manually.
107 |
108 | The example below shows an example of how you could use the facade to validate an email address:
109 |
110 | ```php
111 | use MailboxLayer;
112 |
113 | return MailboxLayer::check('example@domain.com');
114 | ```
115 |
116 | ### Available Validation Result Properties
117 |
118 |
119 | | Field | Description |
120 | |-------------|-------------------------------------------------------------------------------------------------------|
121 | | email | The email address that the validation was carried out on. |
122 | | didYouMean | A suggested email address in case a typo was detected. |
123 | | user | The local part of the email address. Example: 'mail' in 'mail@ashallendesign.co.uk'. |
124 | | domain | The domain part of the email address. Example: 'ashallendesign.co.uk' in 'mail@ashallendesign.co.uk'. |
125 | | formatValid | Whether or not the syntax of the requested email is valid. |
126 | | mxFound | Whether or not the MX records for the requested domain could be found. |
127 | | smtpCheck | Whether or not the SMTP check of the requested email address succeeded. |
128 | | catchAll | Whether or not the requested email address is found to be part of a catch-all mailbox. |
129 | | role | Whether or not the requested email is a role email address. Example: 'support@ashallendesign.co.uk'. |
130 | | disposable | Whether or not the requested email is disposable. Example: 'hello@mailinator.com'. |
131 | | free | Whether or not the requested email is a free email address. |
132 | | score | A score between 0 and 1 reflecting the quality and deliverability of the requested email address. |
133 | | validatedAt | A ` Carbon ` object containing the date and time that the original validation API request was made. |
134 |
135 | ### Caching
136 | #### Caching Validation Results
137 | There might be times when you want to cache the validation results for an email. This can have significant performance benefits for if
138 | you try to validate the email again, due to the fact that the results will be fetched from the cache rather than from a new API request.
139 |
140 | As an example, if you were importing a CSV containing email addresses, you might want to validate each of the addresses. However, if the
141 | CSV contains some duplicated email addresses, it could lead to unnecessary API calls being made. So, by using the caching, each unique
142 | address would only be fetched once from the API. To do this, you can use the ` shouldCache() ` method.
143 |
144 | Using caching is recommended as it reduces the chances of you reaching the monthly request limits or rate limits that are
145 | used by Mailbox Layer. Read more about the [API limits here](https://mailboxlayer.com/documentation#rate_limits).
146 |
147 | The example below shows how to cache the validation results:
148 |
149 | ```php
150 | use AshAllenDesign\MailboxLayer\Classes\MailboxLayer;
151 |
152 | $mailboxLayer = new MailboxLayer('api-key-here');
153 |
154 | // Result fetched from the API.
155 | $validationResults = $mailboxLayer->shouldCache()->check('example@domain.com');
156 |
157 | // Result fetched from the cache.
158 | $validationResults = $mailboxLayer->shouldCache()->check('example@domain.com');
159 | ```
160 |
161 | #### Busting the Cached Validation Results
162 | By default, the package will always try to fetch the validation results from the cache before trying to fetch them via the API.
163 | As mentioned before, this can lead to multiple performance benefits.
164 |
165 | However, there may be times that you want to ignore the cached results and make a new request to the API. As an example, you
166 | might have a cached validation result that is over 6 months old and could possibly be outdated or inaccurate, so it's likely
167 | that you want to update the validation data and ensure it is correct. To do this, you can use the ` fresh() ` method.
168 |
169 | The example below shows how to fetch a new validation result:
170 |
171 | ```php
172 | use AshAllenDesign\MailboxLayer\Classes\MailboxLayer;
173 |
174 | $mailboxLayer = new MailboxLayer('api-key-here');
175 |
176 | $validationResults = $mailboxLayer->fresh()->check('example@domain.com');
177 | ```
178 |
179 | ### Options
180 | #### Using HTTPS
181 |
182 | By default, all the API requests are made using HTTPS. However, the [Mailbox Layer API](https://mailboxlayer.com/)
183 | allows for requests to be made using HTTP if needed. This can be particularly useful when working in a local, development environment.
184 | To use HTTP when making the API requests, you can use the ` withHttps() ` method.
185 |
186 | Please note, it is not recommended making the requests over HTTP in a live, production environment!
187 |
188 | The example below shows how to make the requests using HTTP rather than HTTPS:
189 |
190 | ```php
191 | use AshAllenDesign\MailboxLayer\Classes\MailboxLayer;
192 |
193 | $mailboxLayer = new MailboxLayer('api-key-here');
194 |
195 | $validationResults = $mailboxLayer->withHttps(false)->check('example@domain.com');
196 | ```
197 |
198 | #### Running an SMTP Check
199 |
200 | By default, all the API requests will run an SMTP check on the email address. Running this check can improve the accuracy
201 | of the results and give better results. However, according to Mailbox Layer, running this checks take up around 75% of the
202 | API's entire response time.
203 |
204 | So, you can reduce the overall runtime before preventing the SMTP check from running by using the ` withSmtpCheck() ` method.
205 |
206 | The example below shows how to validate an email address without running an SMTP check:
207 |
208 | ```php
209 | use AshAllenDesign\MailboxLayer\Classes\MailboxLayer;
210 |
211 | $mailboxLayer = new MailboxLayer('api-key-here');
212 |
213 | $validationResults = $mailboxLayer->withSmtpCheck(false)->check('example@domain.com');
214 | ```
215 |
216 |
217 | Read more about the SMTP check in the [Mailbox Layer API docs](https://mailboxlayer.com/documentation#smtp_mx_check).
218 |
219 | ## Testing
220 |
221 | ```bash
222 | vendor/bin/phpunit
223 | ```
224 |
225 | ## Security
226 |
227 | If you find any security related issues, please contact me directly at [mail@ashallendesign.co.uk](mailto:mail@ashallendesign.co.uk) to report it.
228 |
229 | ## Contribution
230 |
231 | If you wish to make any changes or improvements to the package, feel free to make a pull request.
232 |
233 | To contribute to this library, please use the following guidelines before submitting your pull request:
234 |
235 | - Write tests for any new functions that are added. If you are updating existing code, make sure that the existing tests
236 | pass and write more if needed.
237 | - Follow [PSR-2](https://www.php-fig.org/psr/psr-2/) coding standards.
238 | - Make all pull requests to the ``` master ``` branch.
239 |
240 | ## Credits
241 |
242 | - [Ash Allen](https://ashallendesign.co.uk)
243 | - [Jess Pickup](https://jesspickup.co.uk) (Logo)
244 | - [All Contributors](https://github.com/ash-jc-allen/laravel-mailboxlayer/graphs/contributors)
245 |
246 | ## Changelog
247 |
248 | Check the [CHANGELOG](CHANGELOG.md) to get more information about the latest changes.
249 |
250 | ## License
251 |
252 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
253 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ashallendesign/laravel-mailboxlayer",
3 | "description": "A lightweight Laravel package for validating emails using the Mailbox Layer API.",
4 | "type": "library",
5 | "homepage": "https://github.com/ash-jc-allen/laravel-mailboxlayer",
6 | "license": "MIT",
7 | "authors": [
8 | {
9 | "name": "Ash Allen",
10 | "email": "mail@ashallendesign.co.uk"
11 | }
12 | ],
13 | "keywords": [
14 | "ashallendesign",
15 | "laravel",
16 | "laravel-package",
17 | "mailboxlayer",
18 | "email",
19 | "validation"
20 | ],
21 | "require": {
22 | "php": "^7.3|^8.0",
23 | "illuminate/container": "^7.0|^8.0",
24 | "guzzlehttp/guzzle": "^6.3|^7.0"
25 | },
26 | "require-dev": {
27 | "mockery/mockery": "^1.0",
28 | "orchestra/testbench": "^4.0|^5.0|^6.0",
29 | "phpunit/phpunit": "^8.2",
30 | "nunomaduro/larastan": "^0.6.11"
31 | },
32 | "autoload": {
33 | "psr-4": {
34 | "AshAllenDesign\\MailboxLayer\\": "src/"
35 | }
36 | },
37 | "autoload-dev": {
38 | "psr-4": {
39 | "AshAllenDesign\\MailboxLayer\\Tests\\": "tests/"
40 | }
41 | },
42 | "extra": {
43 | "laravel": {
44 | "providers": [
45 | "AshAllenDesign\\MailboxLayer\\Providers\\MailboxLayerProvider"
46 | ],
47 | "aliases": {
48 | "MailboxLayer": "AshAllenDesign\\MailboxLayer\\Facades\\MailboxLayer"
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/config/mailbox-layer.php:
--------------------------------------------------------------------------------
1 | env('MAILBOX_LAYER_API_KEY'),
14 |
15 | ];
16 |
--------------------------------------------------------------------------------
/docs/images/check-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ash-jc-allen/laravel-mailboxlayer/6977f4a52fce78cfd823317435102d58287ca158/docs/images/check-image.png
--------------------------------------------------------------------------------
/phpstan.neon:
--------------------------------------------------------------------------------
1 | includes:
2 | - ./vendor/nunomaduro/larastan/extension.neon
3 |
4 | parameters:
5 | paths:
6 | - src
7 | - tests
8 |
9 | # The level 8 is the highest level
10 | level: 8
11 |
12 | ignoreErrors:
13 | - '#Unsafe usage of new static#'
14 |
15 | excludes_analyse:
16 | - ./*/*/FileToBeExcluded.php
17 |
18 | checkMissingIterableValueType: false
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 | tests
15 |
16 |
17 |
18 |
19 | src/
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/Classes/MailboxLayer.php:
--------------------------------------------------------------------------------
1 | apiKey = $apiKey;
64 | }
65 |
66 | /**
67 | * Run a validation check against the email address.
68 | * Once this has been done, return the results in
69 | * a ValidationObject.
70 | *
71 | * @param string $emailAddress
72 | * @return ValidationResult
73 | *
74 | * @throws MailboxLayerException
75 | */
76 | public function check(string $emailAddress): ValidationResult
77 | {
78 | $cacheKey = $this->buildCacheKey($emailAddress);
79 |
80 | if ($this->fresh) {
81 | Cache::forget($cacheKey);
82 | } else {
83 | $cached = Cache::get($cacheKey);
84 |
85 | if ($cached) {
86 | $result = ValidationResult::makeFromResponse($cached);
87 | }
88 | }
89 |
90 | if (! isset($result)) {
91 | $result = $this->fetchFromApi($emailAddress);
92 | }
93 |
94 | if ($this->shouldCache) {
95 | Cache::forever($cacheKey, (array) $result);
96 | }
97 |
98 | return $result;
99 | }
100 |
101 | /**
102 | * Run validation checks on more than one email address.
103 | * Add each of the results to a Collection and then
104 | * return it.
105 | *
106 | * @param array $emailAddresses
107 | * @return Collection
108 | *
109 | * @throws MailboxLayerException
110 | */
111 | public function checkMany(array $emailAddresses): Collection
112 | {
113 | $results = collect();
114 |
115 | foreach ($emailAddresses as $email) {
116 | $results->push($this->check($email));
117 | }
118 |
119 | return $results;
120 | }
121 |
122 | /**
123 | * Whether or not the email validation result should
124 | * be cached after it's fetched from the API.
125 | *
126 | * @param bool $shouldCache
127 | * @return $this
128 | */
129 | public function shouldCache(bool $shouldCache = true): self
130 | {
131 | $this->shouldCache = $shouldCache;
132 |
133 | return $this;
134 | }
135 |
136 | /**
137 | * Whether or not a fresh result should be fetched from
138 | * the API. Setting field this to true will ignore
139 | * any cached values. It will also delete the
140 | * previously cached result if one exists.
141 | *
142 | * @param bool $fresh
143 | * @return $this
144 | */
145 | public function fresh(bool $fresh = true): self
146 | {
147 | $this->fresh = $fresh;
148 |
149 | return $this;
150 | }
151 |
152 | /**
153 | * Determine whether if HTTPS should be used when
154 | * making the API request.
155 | *
156 | * @param bool $https
157 | * @return $this
158 | */
159 | public function withHttps(bool $https = true): self
160 | {
161 | $this->withHttps = $https;
162 |
163 | return $this;
164 | }
165 |
166 | /**
167 | * Determine whether if an SMTP check should be used
168 | * when validating the address. By not running the
169 | * SMTP check, the API response time will be
170 | * decreased.
171 | *
172 | * @param bool $smtpCheck
173 | * @return $this
174 | */
175 | public function withSmtpCheck(bool $smtpCheck = true): self
176 | {
177 | $this->smtpCheck = $smtpCheck;
178 |
179 | return $this;
180 | }
181 |
182 | /**
183 | * Build the URL that the request will be made to.
184 | *
185 | * @param string $emailAddress
186 | * @return string
187 | */
188 | private function buildUrl(string $emailAddress): string
189 | {
190 | $protocol = $this->withHttps ? 'https://' : 'http://';
191 |
192 | $params = http_build_query([
193 | 'access_key' => $this->apiKey,
194 | 'email' => $emailAddress,
195 | 'smtp' => $this->smtpCheck,
196 | ]);
197 |
198 | return $protocol.self::BASE_URL.'?'.$params;
199 | }
200 |
201 | /**
202 | * Make a request to the API and fetch a new result.
203 | *
204 | * @param string $emailAddress
205 | * @return ValidationResult
206 | *
207 | * @throws MailboxLayerException
208 | */
209 | private function fetchFromApi(string $emailAddress): ValidationResult
210 | {
211 | $response = Http::get($this->buildUrl($emailAddress));
212 |
213 | if (isset($response->json()['error'])) {
214 | $error = $response->json()['error'];
215 |
216 | throw new MailboxLayerException($error['info'], $error['code']);
217 | }
218 |
219 | return ValidationResult::makeFromResponse($response->json());
220 | }
221 |
222 | /**
223 | * Build and return the key that will be used when
224 | * setting or getting the validation result from
225 | * the cache.
226 | *
227 | * @param string $emailAddress
228 | * @return string
229 | */
230 | private function buildCacheKey(string $emailAddress): string
231 | {
232 | return 'mailboxlayer_result_'.$emailAddress;
233 | }
234 | }
235 |
--------------------------------------------------------------------------------
/src/Classes/ValidationResult.php:
--------------------------------------------------------------------------------
1 | $value) {
128 | $objectFieldName = Str::camel((string) $fieldName);
129 | $validationResult->{$objectFieldName} = $value;
130 | }
131 |
132 | if (empty($validationResult->validatedAt)) {
133 | $validationResult->validatedAt = now();
134 | }
135 |
136 | return $validationResult;
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/src/Exceptions/MailboxLayerException.php:
--------------------------------------------------------------------------------
1 | mergeConfigFrom(__DIR__.'/../../config/mailbox-layer.php', 'mailbox-layer');
18 |
19 | $this->app->bind('mailbox-layer', function ($app) {
20 | return new MailboxLayer(config('mailbox-layer.api_key'));
21 | });
22 | }
23 |
24 | /**
25 | * Bootstrap any application services.
26 | *
27 | * @return void
28 | */
29 | public function boot(): void
30 | {
31 | // Config
32 | $this->publishes([
33 | __DIR__.'/../../config/mailbox-layer.php' => config_path('mailbox-layer.php'),
34 | ], 'mailbox-layer-config');
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tests/Unit/Classes/MailboxLayer/CheckManyTest.php:
--------------------------------------------------------------------------------
1 | once()
21 | ->withArgs(['mailboxlayer_result_mail@ashallendesign.co.uk'])
22 | ->andReturnNull();
23 |
24 | Cache::shouldReceive('get')
25 | ->once()
26 | ->withArgs(['mailboxlayer_result_support1@ashallendesign.co.uk'])
27 | ->andReturnNull();
28 |
29 | Http::fake([
30 | 'https://apilayer.net/api/check?access_key=123&email=mail%40ashallendesign.co.uk&smtp=1' => Http::response([
31 | 'email' => 'mail@ashallendesign.co.uk',
32 | 'didYouMean' => '',
33 | 'user' => 'mail',
34 | 'domain' => 'ashallendesign.co.uk',
35 | 'formatValid' => true,
36 | 'mxFound' => true,
37 | 'smtpCheck' => true,
38 | 'catchAll' => false,
39 | 'role' => true,
40 | 'disposable' => false,
41 | 'free' => false,
42 | 'score' => 0.8,
43 | ]),
44 | 'https://apilayer.net/api/check?access_key=123&email=support1%40ashallendesign.co.uk&smtp=1' => Http::response([
45 | 'email' => 'support1@ashallendesign.co.uk',
46 | 'didYouMean' => 'support@ashallendesign.co.uk',
47 | 'user' => 'support1',
48 | 'domain' => 'ashallendesign.co.uk',
49 | 'formatValid' => false,
50 | 'mxFound' => false,
51 | 'smtpCheck' => false,
52 | 'catchAll' => true,
53 | 'role' => false,
54 | 'disposable' => true,
55 | 'free' => true,
56 | 'score' => 0.7,
57 | ]),
58 | ]);
59 |
60 | $mailboxLayer = new MailboxLayer(123);
61 |
62 | $result = $mailboxLayer->checkMany(['mail@ashallendesign.co.uk', 'support1@ashallendesign.co.uk']);
63 | $this->assertInstanceOf(Collection::class, $result);
64 |
65 | $this->assertSame('mail@ashallendesign.co.uk', $result[0]->email);
66 | $this->assertSame('', $result[0]->didYouMean);
67 | $this->assertSame('mail', $result[0]->user);
68 | $this->assertSame('ashallendesign.co.uk', $result[0]->domain);
69 | $this->assertTrue($result[0]->formatValid);
70 | $this->assertTrue($result[0]->smtpCheck);
71 | $this->assertTrue($result[0]->role);
72 | $this->assertFalse($result[0]->disposable);
73 | $this->assertFalse($result[0]->free);
74 | $this->assertSame(0.8, $result[0]->score);
75 | $this->assertEquals(now(), $result[0]->validatedAt);
76 |
77 | $this->assertSame('support1@ashallendesign.co.uk', $result[1]->email);
78 | $this->assertSame('support@ashallendesign.co.uk', $result[1]->didYouMean);
79 | $this->assertSame('support1', $result[1]->user);
80 | $this->assertSame('ashallendesign.co.uk', $result[1]->domain);
81 | $this->assertFalse($result[1]->formatValid);
82 | $this->assertFalse($result[1]->smtpCheck);
83 | $this->assertFalse($result[1]->role);
84 | $this->assertTrue($result[1]->disposable);
85 | $this->assertTrue($result[1]->free);
86 | $this->assertSame(0.7, $result[1]->score);
87 | $this->assertEquals(now(), $result[1]->validatedAt);
88 | }
89 |
90 | /** @test */
91 | public function many_emails_can_be_validated_via_the_cache()
92 | {
93 | // Set a cached value that we can get.
94 | Cache::shouldReceive('get')
95 | ->once()
96 | ->withArgs(['mailboxlayer_result_mail@ashallendesign.co.uk'])
97 | ->andReturn([
98 | 'email' => 'mail@ashallendesign.co.uk',
99 | 'didYouMean' => '',
100 | 'user' => 'mail',
101 | 'domain' => 'ashallendesign.co.uk',
102 | 'formatValid' => true,
103 | 'mxFound' => true,
104 | 'smtpCheck' => true,
105 | 'catchAll' => false,
106 | 'role' => true,
107 | 'disposable' => false,
108 | 'free' => false,
109 | 'score' => 0.8,
110 | 'validatedAt' => now()->subDays(5)->startOfDay(),
111 | ]);
112 |
113 | // Set a cached value that we can get.
114 | Cache::shouldReceive('get')
115 | ->once()
116 | ->withArgs(['mailboxlayer_result_support1@ashallendesign.co.uk'])
117 | ->andReturn([
118 | 'email' => 'support1@ashallendesign.co.uk',
119 | 'didYouMean' => 'support@ashallendesign.co.uk',
120 | 'user' => 'support1',
121 | 'domain' => 'ashallendesign.co.uk',
122 | 'formatValid' => false,
123 | 'mxFound' => false,
124 | 'smtpCheck' => false,
125 | 'catchAll' => true,
126 | 'role' => false,
127 | 'disposable' => true,
128 | 'free' => true,
129 | 'score' => 0.7,
130 | 'validatedAt' => now()->subYear()->startOfDay(),
131 | ]);
132 |
133 | // Assert that the HTTP client is never called.
134 | Http::shouldReceive('get')->never();
135 |
136 | $mailboxLayer = new MailboxLayer(123);
137 |
138 | $result = $mailboxLayer->checkMany(['mail@ashallendesign.co.uk', 'support1@ashallendesign.co.uk']);
139 | $this->assertInstanceOf(Collection::class, $result);
140 |
141 | $this->assertSame('mail@ashallendesign.co.uk', $result[0]->email);
142 | $this->assertSame('', $result[0]->didYouMean);
143 | $this->assertSame('mail', $result[0]->user);
144 | $this->assertSame('ashallendesign.co.uk', $result[0]->domain);
145 | $this->assertTrue($result[0]->formatValid);
146 | $this->assertTrue($result[0]->smtpCheck);
147 | $this->assertTrue($result[0]->role);
148 | $this->assertFalse($result[0]->disposable);
149 | $this->assertFalse($result[0]->free);
150 | $this->assertSame(0.8, $result[0]->score);
151 | $this->assertEquals(now()->subDays(5)->startOfDay(), $result[0]->validatedAt);
152 |
153 | $this->assertSame('support1@ashallendesign.co.uk', $result[1]->email);
154 | $this->assertSame('support@ashallendesign.co.uk', $result[1]->didYouMean);
155 | $this->assertSame('support1', $result[1]->user);
156 | $this->assertSame('ashallendesign.co.uk', $result[1]->domain);
157 | $this->assertFalse($result[1]->formatValid);
158 | $this->assertFalse($result[1]->smtpCheck);
159 | $this->assertFalse($result[1]->role);
160 | $this->assertTrue($result[1]->disposable);
161 | $this->assertTrue($result[1]->free);
162 | $this->assertSame(0.7, $result[1]->score);
163 | $this->assertEquals(now()->subYear()->startOfDay(), $result[1]->validatedAt);
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/tests/Unit/Classes/MailboxLayer/CheckTest.php:
--------------------------------------------------------------------------------
1 | once()
30 | ->withArgs(['mailboxlayer_result_mail@ashallendesign.co.uk'])
31 | ->andReturn($this->responseStructure());
32 |
33 | // Assert that the HTTP client is never called.
34 | Http::shouldReceive('get')->never();
35 |
36 | $mailboxLayer = new MailboxLayer(123);
37 |
38 | $result = $mailboxLayer->check('mail@ashallendesign.co.uk');
39 |
40 | $this->assertValidationResultIsCorrect($result);
41 | }
42 |
43 | /** @test */
44 | public function result_is_returned_from_the_api_if_fresh_is_set_to_false_but_it_does_not_exist_in_the_cache()
45 | {
46 | // Set a cached value that we can get.
47 | Cache::shouldReceive('get')
48 | ->once()
49 | ->withArgs(['mailboxlayer_result_mail@ashallendesign.co.uk'])
50 | ->andReturnNull();
51 |
52 | // Mock the API response.
53 | Http::fake(function () {
54 | return Http::response($this->responseStructure());
55 | });
56 |
57 | $mailboxLayer = new MailboxLayer(123);
58 |
59 | $result = $mailboxLayer->check('mail@ashallendesign.co.uk');
60 |
61 | $this->assertValidationResultIsCorrect($result);
62 |
63 | Http::assertSent(function (Request $request) {
64 | return $request->url() === 'https://apilayer.net/api/check?access_key=123&email=mail%40ashallendesign.co.uk&smtp=1';
65 | });
66 | }
67 |
68 | /** @test */
69 | public function result_is_returned_from_the_api_if_fresh_is_set_to_true()
70 | {
71 | Cache::shouldReceive('forget')
72 | ->withArgs(['mailboxlayer_result_mail@ashallendesign.co.uk'])
73 | ->once()
74 | ->andReturnTrue();
75 |
76 | Cache::shouldReceive('get')->never();
77 |
78 | Cache::shouldReceive('forever')->never();
79 |
80 | // Mock the API response.
81 | Http::fake(function () {
82 | return Http::response($this->responseStructure());
83 | });
84 |
85 | $mailboxLayer = new MailboxLayer(123);
86 |
87 | $result = $mailboxLayer->fresh()->check('mail@ashallendesign.co.uk');
88 |
89 | $this->assertValidationResultIsCorrect($result);
90 |
91 | Http::assertSent(function (Request $request) {
92 | return $request->url() === 'https://apilayer.net/api/check?access_key=123&email=mail%40ashallendesign.co.uk&smtp=1';
93 | });
94 | }
95 |
96 | /** @test */
97 | public function result_is_cached_if_should_bust_cache_is_set_to_true()
98 | {
99 | // Mock the API response.
100 | Http::fake(function () {
101 | return Http::response($this->responseStructure());
102 | });
103 |
104 | Cache::shouldReceive('get')->once()->andReturnNull();
105 |
106 | Cache::shouldReceive('forever')
107 | ->withArgs([
108 | 'mailboxlayer_result_mail@ashallendesign.co.uk',
109 | array_merge($this->responseStructure(), ['validatedAt' => now()]),
110 | ])
111 | ->once()
112 | ->andReturnTrue();
113 |
114 | $mailboxLayer = new MailboxLayer(123);
115 |
116 | $result = $mailboxLayer->shouldCache()->check('mail@ashallendesign.co.uk');
117 |
118 | $this->assertValidationResultIsCorrect($result);
119 |
120 | Http::assertSent(function (Request $request) {
121 | return $request->url() === 'https://apilayer.net/api/check?access_key=123&email=mail%40ashallendesign.co.uk&smtp=1';
122 | });
123 | }
124 |
125 | /** @test */
126 | public function email_can_be_validated_without_the_smtp_check()
127 | {
128 | // Mock the API response.
129 | Http::fake(function () {
130 | return Http::response($this->responseStructure());
131 | });
132 |
133 | $mailboxLayer = new MailboxLayer(123);
134 |
135 | $result = $mailboxLayer->withSmtpCheck(false)->check('mail@ashallendesign.co.uk');
136 |
137 | $this->assertValidationResultIsCorrect($result);
138 |
139 | Http::assertSent(function (Request $request) {
140 | return $request->url() === 'https://apilayer.net/api/check?access_key=123&email=mail%40ashallendesign.co.uk&smtp=0';
141 | });
142 | }
143 |
144 | /** @test */
145 | public function request_can_be_sent_without_using_https()
146 | {
147 | // Mock the API response.
148 | Http::fake(function () {
149 | return Http::response($this->responseStructure());
150 | });
151 |
152 | $mailboxLayer = new MailboxLayer(123);
153 |
154 | $result = $mailboxLayer->withHttps(false)->check('mail@ashallendesign.co.uk');
155 |
156 | $this->assertValidationResultIsCorrect($result);
157 |
158 | Http::assertSent(function (Request $request) {
159 | return $request->url() === 'http://apilayer.net/api/check?access_key=123&email=mail%40ashallendesign.co.uk&smtp=1';
160 | });
161 | }
162 |
163 | /** @test */
164 | public function exception_is_thrown_if_the_api_request_returns_an_error()
165 | {
166 | $this->expectException(MailboxLayerException::class);
167 | $this->expectExceptionCode(101);
168 | $this->expectExceptionMessage('You have not supplied a valid API Access Key. [Technical Support: support@apilayer.com]');
169 |
170 | // Mock the API response.
171 | Http::fake(function () {
172 | return Http::response($this->errorResponseStructure());
173 | });
174 |
175 | $mailboxLayer = new MailboxLayer(123);
176 |
177 | $result = $mailboxLayer->withHttps(false)->check('mail@ashallendesign.co.uk');
178 |
179 | $this->assertValidationResultIsCorrect($result);
180 |
181 | Http::assertSent(function (Request $request) {
182 | return $request->url() === 'http://apilayer.net/api/check?access_key=123&email=mail%40ashallendesign.co.uk&smtp=1';
183 | });
184 | }
185 |
186 | /** @test */
187 | public function validation_can_be_carried_out_using_the_facade()
188 | {
189 | // Set the API key in the config so that it can be used when
190 | // creating the facade.
191 | config(['mailbox-layer.api_key' => 123]);
192 |
193 | // Mock the API response.
194 | Http::fake(function () {
195 | return Http::response($this->responseStructure());
196 | });
197 |
198 | $result = MailboxLayerFacade::withHttps(false)->check('mail@ashallendesign.co.uk');
199 |
200 | $this->assertValidationResultIsCorrect($result);
201 |
202 | Http::assertSent(function (Request $request) {
203 | return $request->url() === 'http://apilayer.net/api/check?access_key=123&email=mail%40ashallendesign.co.uk&smtp=1';
204 | });
205 | }
206 |
207 | private function responseStructure(): array
208 | {
209 | return [
210 | 'email' => 'mail@ashallendesign.co.uk',
211 | 'didYouMean' => '',
212 | 'user' => 'mail',
213 | 'domain' => 'ashallendesign.co.uk',
214 | 'formatValid' => true,
215 | 'mxFound' => true,
216 | 'smtpCheck' => true,
217 | 'catchAll' => false,
218 | 'role' => true,
219 | 'disposable' => false,
220 | 'free' => false,
221 | 'score' => 0.8,
222 | ];
223 | }
224 |
225 | private function errorResponseStructure(): array
226 | {
227 | return [
228 | 'success' => false,
229 | 'error' => [
230 | 'code' => '101',
231 | 'type' => 'invalid_access_key',
232 | 'info' => 'You have not supplied a valid API Access Key. [Technical Support: support@apilayer.com]',
233 | ],
234 | ];
235 | }
236 |
237 | private function assertValidationResultIsCorrect(ValidationResult $result): void
238 | {
239 | $this->assertSame('mail@ashallendesign.co.uk', $result->email);
240 | $this->assertSame('', $result->didYouMean);
241 | $this->assertSame('mail', $result->user);
242 | $this->assertSame('ashallendesign.co.uk', $result->domain);
243 | $this->assertTrue($result->formatValid);
244 | $this->assertTrue($result->smtpCheck);
245 | $this->assertTrue($result->role);
246 | $this->assertFalse($result->disposable);
247 | $this->assertFalse($result->free);
248 | $this->assertSame(0.8, $result->score);
249 | $this->assertEquals(now(), $result->validatedAt);
250 | }
251 | }
252 |
--------------------------------------------------------------------------------
/tests/Unit/Classes/ValidationResult/MakeFromResponseTest.php:
--------------------------------------------------------------------------------
1 | 'mai1l@ashallendesign.co.uk',
18 | 'did_you_mean' => 'mail@ashallendesign.co.uk',
19 | 'user' => 'mai1l',
20 | 'domain' => 'ashallendesign.co.uk',
21 | 'format_valid' => true,
22 | 'smtp_check' => true,
23 | 'role' => true,
24 | 'disposable' => false,
25 | 'free' => false,
26 | 'score' => 0.8,
27 | 'validated_at' => now(),
28 | ];
29 |
30 | $newObject = ValidationResult::makeFromResponse($responseData);
31 |
32 | $this->assertSame('mai1l@ashallendesign.co.uk', $newObject->email);
33 | $this->assertSame('mail@ashallendesign.co.uk', $newObject->didYouMean);
34 | $this->assertSame('mai1l', $newObject->user);
35 | $this->assertSame('ashallendesign.co.uk', $newObject->domain);
36 | $this->assertTrue($newObject->formatValid);
37 | $this->assertTrue($newObject->smtpCheck);
38 | $this->assertTrue($newObject->role);
39 | $this->assertFalse($newObject->disposable);
40 | $this->assertFalse($newObject->free);
41 | $this->assertSame(0.8, $newObject->score);
42 | $this->assertEquals(now(), $newObject->validatedAt);
43 | }
44 |
45 | /** @test */
46 | public function new_object_is_returned_with_correct_fields_set_and_the_validatedAt_date_is_not_already_set()
47 | {
48 | Carbon::setTestNow(now());
49 |
50 | $responseData = [
51 | 'email' => 'mai1l@ashallendesign.co.uk',
52 | 'did_you_mean' => 'mail@ashallendesign.co.uk',
53 | 'user' => 'mai1l',
54 | 'domain' => 'ashallendesign.co.uk',
55 | 'format_valid' => true,
56 | 'smtp_check' => true,
57 | 'role' => true,
58 | 'disposable' => false,
59 | 'free' => false,
60 | 'score' => 0.8,
61 | ];
62 |
63 | $newObject = ValidationResult::makeFromResponse($responseData);
64 |
65 | $this->assertSame('mai1l@ashallendesign.co.uk', $newObject->email);
66 | $this->assertSame('mail@ashallendesign.co.uk', $newObject->didYouMean);
67 | $this->assertSame('mai1l', $newObject->user);
68 | $this->assertSame('ashallendesign.co.uk', $newObject->domain);
69 | $this->assertTrue($newObject->formatValid);
70 | $this->assertTrue($newObject->smtpCheck);
71 | $this->assertTrue($newObject->role);
72 | $this->assertFalse($newObject->disposable);
73 | $this->assertFalse($newObject->free);
74 | $this->assertSame(0.8, $newObject->score);
75 | $this->assertEquals(now(), $newObject->validatedAt);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/tests/Unit/TestCase.php:
--------------------------------------------------------------------------------
1 | MailboxLayer::class,
32 | ];
33 | }
34 | }
35 |
--------------------------------------------------------------------------------