is-noise-email.ts2.0 KBView on GitHub /**
* Heuristics for filtering out non-human / automated contacts that get auto-added
* to conversations (mailer-daemons, notification senders, the user themselves, etc.).
*/
const AUTOMATED_LOCAL_PARTS = new Set([
'noreply',
'no-reply',
'donotreply',
'do-not-reply',
'mailer-daemon',
'postmaster',
'notifications',
'notification',
'notify',
'alerts',
'alert',
'bounce',
'bounces',
'hello',
]);
function extractDomain(email: string): string {
const parts = email.toLowerCase().split('@');
return parts.length > 1 ? parts[1] : '';
}
function extractLocalPart(email: string): string {
return email.toLowerCase().split('@')[0] ?? '';
}
/**
* Automated/system senders — bouncers, transactional notifications, no-reply, etc.
*/
export function isAutomatedSenderEmail(email: string): boolean {
const local = extractLocalPart(email);
if (AUTOMATED_LOCAL_PARTS.has(local)) return true;
// Catch variants like `notifications-foo@`, `no-reply+x@`, `mailer-daemon-...@`
for (const prefix of AUTOMATED_LOCAL_PARTS) {
if (local.startsWith(`${prefix}+`) || local.startsWith(`${prefix}-`)) return true;
}
return false;
}
/**
* True when the email shares the user's own domain (or is the user's exact address).
* Handles the consumer-domain case where the full email is stored as a "domain".
*/
export function isInternalEmail(email: string, userEmail: string | null | undefined): boolean {
if (!userEmail) return false;
const normalizedEmail = email.toLowerCase();
const normalizedUserEmail = userEmail.toLowerCase();
if (normalizedEmail === normalizedUserEmail) return true;
const emailDomain = extractDomain(normalizedEmail);
const userDomain = extractDomain(normalizedUserEmail);
return emailDomain !== '' && emailDomain === userDomain;
}
/**
* Combined predicate: should this contact be hidden from human-facing contact lists?
*/
export function isNoiseContactEmail(
email: string,
userEmail: string | null | undefined,
): boolean {
return isAutomatedSenderEmail(email) || isInternalEmail(email, userEmail);
}