Skip to content

Commit fcdbdde

Browse files
Update CHANGELOG.md
Add business email validation and batch features Introduces BusinessEmail validation rule, Sift::rule(), Sift::isBusiness(), batch domain extraction (domains, extractAll), email statistics (stats), and config options for excluding default domains. Default public email providers are now managed internally (DefaultDomains), config is simplified, and Pest 4 is supported. Updates documentation and tests for new features.
1 parent 5ffb469 commit fcdbdde

File tree

10 files changed

+835
-118
lines changed

10 files changed

+835
-118
lines changed

CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,35 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [0.3.0] - 2025-12-07
6+
7+
### Added
8+
- `BusinessEmail` validation rule for requiring business email addresses
9+
- `Sift::rule()` helper to get the validation rule instance
10+
- `Sift::isBusiness()` method to check if email is from a business domain
11+
- `Sift::domains()` for batch extraction from multiple emails
12+
- `Sift::extractAll()` for extracting all domains without filtering
13+
- `Sift::stats()` for email collection statistics (total, business, personal, rate, top domains)
14+
- `Sift::getCommonDomains()` to retrieve the full merged list of filtered domains
15+
- `exclude_default_domains` config option to whitelist specific default providers
16+
- Pest 4 support
17+
- 30+ additional email providers including:
18+
- US ISPs (AT&T, Comcast, Verizon, etc.)
19+
- Privacy-focused (Mailfence, Posteo, Disroot, Countermail)
20+
- Regional providers for Netherlands, Brazil, Spain
21+
- Modern providers (Proton.me, Naver)
22+
- More disposable email services
23+
24+
### Changed
25+
- Default domains now live in package (`DefaultDomains::LIST`) - users automatically get updates
26+
- Config simplified to `additional_domains` and `exclude_default_domains`
27+
- Expanded common domains list from 70+ to 100+ providers
28+
29+
### Removed
30+
- `common_domains` config option (now managed by package internally)
31+
32+
**See [UPGRADE.md](UPGRADE.md) for migration instructions.**
33+
534
## [0.2.0] - 2025-09-18
635

736
### Added

README.md

Lines changed: 140 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ use MischaSigtermans\Sift\Facades\Sift;
1919
Sift::domain('user@company.com'); // 'company.com'
2020
Sift::domain('user@gmail.com'); // null (filtered)
2121

22-
// Include public domains when needed
23-
Sift::domain('user@gmail.com', true); // 'gmail.com'
24-
25-
// Check if a domain is a public provider
26-
Sift::isCommon('gmail.com'); // true
27-
Sift::isCommon('company.com'); // false
22+
// Check if email is business or personal
23+
Sift::isBusiness('user@company.com'); // true
24+
Sift::isBusiness('user@gmail.com'); // false
25+
26+
// Validate in form requests
27+
$request->validate([
28+
'email' => ['required', 'email', Sift::rule()],
29+
]);
2830
```
2931

3032
## Why Sift?
@@ -45,24 +47,26 @@ When collecting emails from users, you often need to distinguish between busines
4547
Extract the domain portion from any email address:
4648

4749
```php
48-
Sift::domain('john.doe@example.com'); // 'example.com'
50+
Sift::domain('john.doe@example.com'); // 'example.com'
4951
Sift::domain('support@sub.domain.org'); // 'sub.domain.org'
5052
```
5153

5254
### Smart Filtering
5355

54-
Public email providers are filtered by default. The package includes 70+ common providers:
56+
Public email providers are filtered by default. The package includes 100+ common providers:
5557

5658
```php
5759
// These return null (filtered as public providers)
5860
Sift::domain('user@gmail.com');
5961
Sift::domain('user@yahoo.com');
6062
Sift::domain('user@outlook.com');
61-
Sift::domain('user@hotmail.com');
6263

6364
// Business domains pass through
6465
Sift::domain('user@stripe.com'); // 'stripe.com'
6566
Sift::domain('user@company.io'); // 'company.io'
67+
68+
// Include public domains when needed
69+
Sift::domain('user@gmail.com', true); // 'gmail.com'
6670
```
6771

6872
### Domain Checking
@@ -73,24 +77,102 @@ Check if a domain or email belongs to a public provider:
7377
Sift::isCommon('gmail.com'); // true
7478
Sift::isCommon('user@protonmail.com'); // true
7579
Sift::isCommon('company.com'); // false
80+
81+
// Or check if it's a business email
82+
Sift::isBusiness('user@company.com'); // true
83+
Sift::isBusiness('user@gmail.com'); // false
84+
```
85+
86+
### Validation Rule
87+
88+
Require business email addresses in form requests:
89+
90+
```php
91+
use MischaSigtermans\Sift\Rules\BusinessEmail;
92+
93+
// Using the rule class directly
94+
$request->validate([
95+
'email' => ['required', 'email', new BusinessEmail],
96+
]);
97+
98+
// Or via the facade helper
99+
$request->validate([
100+
'email' => ['required', 'email', Sift::rule()],
101+
]);
102+
```
103+
104+
Error message: "The email must be a business email address."
105+
106+
### Batch Processing
107+
108+
Process multiple emails at once:
109+
110+
```php
111+
$emails = [
112+
'john@acme.com',
113+
'jane@stripe.com',
114+
'bob@gmail.com',
115+
'alice@acme.com',
116+
];
117+
118+
// Extract unique business domains (filters personal emails)
119+
Sift::domains($emails);
120+
// ['acme.com', 'stripe.com']
121+
122+
// Extract all unique domains without filtering
123+
Sift::extractAll($emails);
124+
// ['acme.com', 'stripe.com', 'gmail.com']
125+
126+
// Include personal domains
127+
Sift::domains($emails, includeCommon: true);
128+
// ['acme.com', 'stripe.com', 'gmail.com']
129+
```
130+
131+
### Statistics
132+
133+
Analyze email collections:
134+
135+
```php
136+
$emails = [
137+
'john@acme.com',
138+
'jane@acme.com',
139+
'bob@stripe.com',
140+
'alice@gmail.com',
141+
'charlie@yahoo.com',
142+
];
143+
144+
$stats = Sift::stats($emails);
145+
// [
146+
// 'total' => 5,
147+
// 'business' => 3,
148+
// 'personal' => 2,
149+
// 'business_rate' => 60.0,
150+
// 'top_domains' => [
151+
// 'acme.com' => 2,
152+
// 'stripe.com' => 1,
153+
// ],
154+
// ]
155+
156+
// Limit top domains returned
157+
$stats = Sift::stats($emails, topDomainsLimit: 5);
76158
```
77159

78160
### Case Insensitive
79161

80162
All comparisons are case-insensitive:
81163

82164
```php
83-
Sift::domain('User@GMAIL.COM'); // null
84-
Sift::domain('User@Company.COM'); // 'company.com'
85-
Sift::isCommon('YAHOO.COM'); // true
165+
Sift::domain('User@GMAIL.COM'); // null
166+
Sift::domain('User@Company.COM'); // 'company.com'
167+
Sift::isCommon('YAHOO.COM'); // true
86168
```
87169

88170
### Blade Support
89171

90172
Use directly in Blade templates:
91173

92174
```blade
93-
@if(Sift::domain($user->email))
175+
@if(Sift::isBusiness($user->email))
94176
<span>{{ Sift::domain($user->email) }}</span>
95177
@else
96178
<span class="text-muted">Personal email</span>
@@ -99,7 +181,9 @@ Use directly in Blade templates:
99181

100182
## Configuration
101183

102-
Publish the config file:
184+
The package includes 100+ public email providers by default. You automatically get updates when the package is updated.
185+
186+
Publish the config file to customize:
103187

104188
```bash
105189
php artisan vendor:publish --tag=sift-config
@@ -108,72 +192,69 @@ php artisan vendor:publish --tag=sift-config
108192
```php
109193
// config/sift.php
110194
return [
111-
/*
112-
|--------------------------------------------------------------------------
113-
| Additional Domains
114-
|--------------------------------------------------------------------------
115-
|
116-
| Add custom domains to filter alongside the built-in common domains.
117-
| Useful for filtering industry-specific providers or internal domains
118-
| you want to exclude from business email detection.
119-
|
120-
*/
195+
// Add extra domains to filter (on top of package defaults)
121196
'additional_domains' => [
122-
// 'competitor.com',
123-
// 'internal-tool.io',
197+
'competitor.com',
198+
'internal-tool.io',
124199
],
125200

126-
/*
127-
|--------------------------------------------------------------------------
128-
| Common Domains
129-
|--------------------------------------------------------------------------
130-
|
131-
| Pre-populated list of public email providers. Includes major providers
132-
| worldwide: Gmail, Yahoo, Outlook, Hotmail, iCloud, ProtonMail, and 60+
133-
| regional and temporary email services.
134-
|
135-
| You can modify this list to match your specific requirements.
136-
|
137-
*/
138-
'common_domains' => [
139-
'gmail.com', 'yahoo.com', 'outlook.com', 'hotmail.com',
140-
// ... 70+ providers included
201+
// Whitelist specific defaults (allow them as business emails)
202+
'exclude_default_domains' => [
203+
'protonmail.com', // Allow privacy-focused provider
204+
'fastmail.com',
141205
],
142206
];
143207
```
144208

209+
### View All Default Domains
210+
211+
```php
212+
use MischaSigtermans\Sift\DefaultDomains;
213+
214+
// Get the full list of 100+ default domains
215+
DefaultDomains::LIST;
216+
217+
// Or get the merged list (defaults + additional - excluded)
218+
Sift::getCommonDomains();
219+
```
220+
145221
## Use Cases
146222

147223
### Lead Form Validation
148224

149225
```php
150226
public function store(Request $request)
151227
{
152-
$request->validate(['email' => 'required|email']);
153-
154-
$domain = Sift::domain($request->email);
155-
156-
if (!$domain) {
157-
return back()->withErrors([
158-
'email' => 'Please use your business email address.'
159-
]);
160-
}
228+
$request->validate([
229+
'email' => ['required', 'email', Sift::rule()],
230+
]);
161231

162232
Lead::create([
163233
'email' => $request->email,
164-
'company_domain' => $domain,
234+
'company_domain' => Sift::domain($request->email),
165235
]);
166236
}
167237
```
168238

239+
### User Analytics Dashboard
240+
241+
```php
242+
public function emailStats()
243+
{
244+
$emails = User::pluck('email');
245+
246+
return Sift::stats($emails);
247+
// Shows business vs personal breakdown with top company domains
248+
}
249+
```
250+
169251
### User Grouping
170252

171253
```php
172254
$users = User::all()->groupBy(function ($user) {
173255
return Sift::domain($user->email, true) ?? 'personal';
174256
});
175257

176-
// Results in:
177258
// [
178259
// 'acme.com' => [...users from acme.com...],
179260
// 'stripe.com' => [...users from stripe.com...],
@@ -186,9 +267,8 @@ $users = User::all()->groupBy(function ($user) {
186267
```php
187268
public function calculateDiscount(User $user): int
188269
{
189-
// Business emails get enterprise pricing
190-
if (Sift::domain($user->email)) {
191-
return 20; // 20% discount
270+
if (Sift::isBusiness($user->email)) {
271+
return 20; // 20% enterprise discount
192272
}
193273

194274
return 0;
@@ -201,6 +281,11 @@ public function calculateDiscount(User $user): int
201281
composer test
202282
```
203283

284+
## Requirements
285+
286+
- PHP 8.2+
287+
- Laravel 9, 10, 11, or 12
288+
204289
## License
205290

206291
MIT

0 commit comments

Comments
 (0)