|
3 | 3 | namespace Utopia\Emails; |
4 | 4 |
|
5 | 5 | use Exception; |
| 6 | +use Utopia\Emails\Normalizer\Provider; |
| 7 | +use Utopia\Emails\Normalizer\Providers\Fastmail; |
| 8 | +use Utopia\Emails\Normalizer\Providers\Generic; |
| 9 | +use Utopia\Emails\Normalizer\Providers\Gmail; |
| 10 | +use Utopia\Emails\Normalizer\Providers\Icloud; |
| 11 | +use Utopia\Emails\Normalizer\Providers\Outlook; |
| 12 | +use Utopia\Emails\Normalizer\Providers\Protonmail; |
| 13 | +use Utopia\Emails\Normalizer\Providers\Yahoo; |
6 | 14 |
|
7 | 15 | class Email |
8 | 16 | { |
@@ -58,6 +66,13 @@ class Email |
58 | 66 | */ |
59 | 67 | protected static $disposableDomains = null; |
60 | 68 |
|
| 69 | + /** |
| 70 | + * Email providers |
| 71 | + * |
| 72 | + * @var Provider[] |
| 73 | + */ |
| 74 | + protected static $providers = null; |
| 75 | + |
61 | 76 | /** |
62 | 77 | * Email constructor. |
63 | 78 | */ |
@@ -268,6 +283,93 @@ public function normalize(): string |
268 | 283 | return $this->email; |
269 | 284 | } |
270 | 285 |
|
| 286 | + /** |
| 287 | + * Get unique email address by removing aliases and provider-specific variations |
| 288 | + * This method removes plus addressing, dot notation (for Gmail), and other aliasing techniques |
| 289 | + * to return the canonical form of the email address |
| 290 | + */ |
| 291 | + public function getUnique(): string |
| 292 | + { |
| 293 | + $provider = $this->getProviderForDomain($this->domain); |
| 294 | + $normalized = $provider->normalize($this->local, $this->domain); |
| 295 | + |
| 296 | + return $normalized['local'].'@'.$normalized['domain']; |
| 297 | + } |
| 298 | + |
| 299 | + /** |
| 300 | + * Check if the email domain is supported for normalization |
| 301 | + */ |
| 302 | + public function isNormalizationSupported(): bool |
| 303 | + { |
| 304 | + return $this->isDomainSupported($this->domain); |
| 305 | + } |
| 306 | + |
| 307 | + /** |
| 308 | + * Get the canonical domain for this email |
| 309 | + */ |
| 310 | + public function getCanonicalDomain(): ?string |
| 311 | + { |
| 312 | + $provider = $this->getProviderForDomain($this->domain); |
| 313 | + |
| 314 | + // Only return canonical domain if it's not the generic provider |
| 315 | + if (! $provider instanceof Generic) { |
| 316 | + return $provider->getCanonicalDomain(); |
| 317 | + } |
| 318 | + |
| 319 | + return null; |
| 320 | + } |
| 321 | + |
| 322 | + /** |
| 323 | + * Get the appropriate provider for a given domain |
| 324 | + */ |
| 325 | + protected function getProviderForDomain(string $domain): Provider |
| 326 | + { |
| 327 | + if (self::$providers === null) { |
| 328 | + self::$providers = [ |
| 329 | + new Gmail, |
| 330 | + new Outlook, |
| 331 | + new Yahoo, |
| 332 | + new Icloud, |
| 333 | + new Protonmail, |
| 334 | + new Fastmail, |
| 335 | + ]; |
| 336 | + } |
| 337 | + |
| 338 | + foreach (self::$providers as $provider) { |
| 339 | + if ($provider->supports($domain)) { |
| 340 | + return $provider; |
| 341 | + } |
| 342 | + } |
| 343 | + |
| 344 | + // Return generic provider if no specific provider found |
| 345 | + return new Generic; |
| 346 | + } |
| 347 | + |
| 348 | + /** |
| 349 | + * Check if a domain is supported by any provider |
| 350 | + */ |
| 351 | + protected function isDomainSupported(string $domain): bool |
| 352 | + { |
| 353 | + if (self::$providers === null) { |
| 354 | + self::$providers = [ |
| 355 | + new Gmail, |
| 356 | + new Outlook, |
| 357 | + new Yahoo, |
| 358 | + new Icloud, |
| 359 | + new Protonmail, |
| 360 | + new Fastmail, |
| 361 | + ]; |
| 362 | + } |
| 363 | + |
| 364 | + foreach (self::$providers as $provider) { |
| 365 | + if ($provider->supports($domain)) { |
| 366 | + return true; |
| 367 | + } |
| 368 | + } |
| 369 | + |
| 370 | + return false; |
| 371 | + } |
| 372 | + |
271 | 373 | /** |
272 | 374 | * Get email in different formats |
273 | 375 | */ |
|
0 commit comments