feat: Add forwarding domains as verification check

This commit is contained in:
Dries Augustyns
2026-01-03 09:54:17 +01:00
parent fb02051538
commit e732c76490
5 changed files with 79 additions and 1 deletions
@@ -8,6 +8,35 @@ const DISPOSABLE_DOMAINS_URL =
const DISPOSABLE_DOMAINS_CACHE_KEY = 'email:disposable_domains';
const CACHE_TTL_SECONDS = 24 * 60 * 60; // 24 hours (list updates daily)
// Known email forwarding/alias services
const FORWARDING_DOMAINS = new Set([
'privaterelay.appleid.com', // Apple Sign In
'mozmail.com', // Firefox Relay
'simplelogin.com', // SimpleLogin
'simplelogin.fr',
'simplelogin.co',
'simplelogin.io',
'aleeas.com',
'slmail.me',
'dralias.com',
'8shield.net',
'anonaddy.com', // Addy.io
'anonaddy.me',
'addy.io',
'duck.com', // DuckDuckGo
'33mail.com', // 33mail
'33m.co',
'passmail.com', // Proton Pass
'passmail.net',
'passinbox.com',
'passfwd.com',
'y.yo.fr',
'opayq.com', // IronVest (formerly Blur)
'cloak.id', // Cloaked
'erine.email', // Erine
'use.startmail.com', // StartMail
]);
export class EmailVerificationService {
private static disposableDomainsSet: Set<string> | null = null;
@@ -16,6 +45,7 @@ export class EmailVerificationService {
* - Checks if domain exists (DNS A/AAAA records)
* - Checks for MX records
* - Detects disposable email addresses
* - Detects forwarding/alias email addresses
* - Suggests corrections for common typos
*/
static async verifyEmail(email: string): Promise<EmailVerificationResult> {
@@ -23,6 +53,7 @@ export class EmailVerificationService {
email,
valid: true,
isDisposable: false,
isAlias: false,
isTypo: false,
isPlusAddressed: false,
domainExists: false,
@@ -43,6 +74,9 @@ export class EmailVerificationService {
// Check if email is from a disposable domain using GitHub list
result.isDisposable = await this.isDisposableDomain(domain);
// Check if email is from a known forwarding/alias service
result.isAlias = this.isForwardingDomain(domain);
// Check for plus addressing
result.isPlusAddressed = emailParts[0]!.includes('+');
@@ -146,4 +180,11 @@ export class EmailVerificationService {
const disposableDomains = await this.getDisposableDomains();
return disposableDomains.has(domain.toLowerCase());
}
/**
* Check if a domain is a known forwarding/alias service
*/
private static isForwardingDomain(domain: string): boolean {
return FORWARDING_DOMAINS.has(domain.toLowerCase());
}
}
@@ -1,4 +1,15 @@
import {AlertCircle, AlertTriangle, CheckCircle, Info, Mail, Server, Shield, Trash2, XCircle} from 'lucide-react';
import {
AlertCircle,
AlertTriangle,
CheckCircle,
Info,
Mail,
Server,
Shield,
Trash2,
XCircle,
Forward,
} from 'lucide-react';
import type {EmailVerificationResult as VerificationResult} from '../../lib/emailVerification';
interface EmailVerificationResultProps {
@@ -83,6 +94,22 @@ export function EmailVerificationResult({result}: EmailVerificationResultProps)
)}
</div>
{/* Alias/Forwarding Email */}
<div className="flex items-center justify-between px-6 py-4">
<div className="flex items-center gap-3">
<Forward className="h-5 w-5 text-neutral-600" />
<div>
<p className="font-medium text-neutral-900">Forwarding Service</p>
<p className="text-sm text-neutral-600">Email alias/forwarding detected</p>
</div>
</div>
{result.isAlias ? (
<Info className="h-5 w-5 text-blue-600" />
) : (
<CheckCircle className="h-5 w-5 text-green-600" />
)}
</div>
{/* Typo Detection */}
<div className="flex items-center justify-between px-6 py-4">
<div className="flex items-center gap-3">
@@ -2,6 +2,7 @@ export interface EmailVerificationResult {
email: string;
valid: boolean;
isDisposable: boolean;
isAlias: boolean;
isTypo: boolean;
isPlusAddressed: boolean;
domainExists: boolean;
+8
View File
@@ -664,6 +664,10 @@
"type": "boolean",
"description": "Whether the email is from a disposable/temporary email domain"
},
"isAlias": {
"type": "boolean",
"description": "Whether the email is from a forwarding/alias service"
},
"isTypo": {
"type": "boolean",
"description": "Whether a potential typo was detected in the email address"
@@ -698,6 +702,7 @@
"email",
"valid",
"isDisposable",
"isAlias",
"isTypo",
"isPlusAddressed",
"domainExists",
@@ -716,6 +721,7 @@
"email": "[email protected]",
"valid": true,
"isDisposable": false,
"isAlias": false,
"isTypo": false,
"isPlusAddressed": false,
"domainExists": true,
@@ -732,6 +738,7 @@
"email": "[email protected]",
"valid": false,
"isDisposable": false,
"isAlias": false,
"isTypo": true,
"isPlusAddressed": false,
"domainExists": false,
@@ -749,6 +756,7 @@
"email": "[email protected]",
"valid": true,
"isDisposable": true,
"isAlias": false,
"isTypo": false,
"isPlusAddressed": false,
"domainExists": true,