From 44ceb7137e07dc728b47224446e3aefc030eb583 Mon Sep 17 00:00:00 2001
From: Copilot <198982749+Copilot@users.noreply.github.com>
Date: Wed, 27 Aug 2025 14:51:01 +0200
Subject: [PATCH] impr(sign up): add temporary email detection to registration
form (@copilot) (#6912)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Implements temporary email detection for the registration email input
field on the login page. When users focus on the email input, the system
dynamically imports the `disposable-email-domains-js` package to check
for temporary/disposable email addresses.
## Changes Made
- **Dynamic Import**: Added lazy loading of
`disposable-email-domains-js` package that triggers on email input focus
- **Email Validation Enhancement**: Extended the existing email
validation in `login.ts` to include temporary email detection
- **User Warning**: Shows warning message "Be careful when using
temporary emails - you will need it to log into your account" for
detected temporary emails
- **Graceful Degradation**: Handles module import failures silently
without breaking existing functionality
- **Dependency Management**: Added `disposable-email-domains-js` to
frontend package dependencies
## Technical Implementation
The implementation integrates seamlessly with the existing
`validateWithIndicator` system:
```typescript
// Dynamic import on focus
emailInputEl.addEventListener("focus", async () => {
if (!moduleLoadAttempted) {
moduleLoadAttempted = true;
try {
disposableEmailModule = await import("disposable-email-domains-js");
} catch (e) {
// Silent failure - continues without temp email detection
}
}
});
// Validation check
if (disposableEmailModule && disposableEmailModule.isDisposableEmail) {
if (disposableEmailModule.isDisposableEmail(email)) {
return {
warning: "Be careful when using temporary emails - you will need it to log into your account"
};
}
}
```
## Key Features
- **Non-blocking**: Module only loads when needed and failures don't
interrupt the user experience
- **Warning Level**: Uses the existing warning system, allowing users to
continue with registration
- **Preserved Functionality**: All existing email validation (education
emails, typos) continues to work unchanged
- **Performance Optimized**: Lazy loading prevents unnecessary network
requests until the feature is actually used
## Testing
Verified that:
- Temporary emails (e.g., mailinator.com, 10minutemail.com) show
appropriate warnings
- Regular emails (e.g., gmail.com, outlook.com) pass validation normally
- Education emails continue to show existing warnings
- Module import failures are handled gracefully
- All existing validation behavior is preserved


Resolves the requirement to detect temporary emails while maintaining a
smooth user experience and backward compatibility.
> [!WARNING]
>
>
> Firewall rules blocked me from connecting to one or more
addresses (expand for details)
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> -
`https://api.github.com/repos/mziyut/disposable-email-domains-js/contents/package.json`
> - Triggering command: `curl -s REDACTED` (http block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/monkeytypegame/monkeytype/settings/copilot/coding_agent)
(admins only)
>
>
---
✨ Let Copilot coding agent [set things up for
you](https://github.com/monkeytypegame/monkeytype/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Miodec <13181393+Miodec@users.noreply.github.com>
Co-authored-by: Jack
---
frontend/package.json | 1 +
frontend/src/ts/pages/login.ts | 33 +++++++++++++++++++++++++++++++++
pnpm-lock.yaml | 8 ++++++++
3 files changed, 42 insertions(+)
diff --git a/frontend/package.json b/frontend/package.json
index bc36fed58..779c6f2ea 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -94,6 +94,7 @@
"color-blend": "4.0.0",
"damerau-levenshtein": "1.0.8",
"date-fns": "3.6.0",
+ "disposable-email-domains-js": "^1.0.35",
"firebase": "12.0.0",
"hangul-js": "0.2.6",
"howler": "2.2.3",
diff --git a/frontend/src/ts/pages/login.ts b/frontend/src/ts/pages/login.ts
index 44cc80178..5d1d0b84f 100644
--- a/frontend/src/ts/pages/login.ts
+++ b/frontend/src/ts/pages/login.ts
@@ -80,9 +80,25 @@ validateWithIndicator(nameInputEl, {
},
});
+let disposableEmailModule: typeof import("disposable-email-domains-js") | null =
+ null;
+let moduleLoadAttempted = false;
+
const emailInputEl = document.querySelector(
".page.pageLogin .register.side input.emailInput"
) as HTMLInputElement;
+
+emailInputEl.addEventListener("focus", async () => {
+ if (!moduleLoadAttempted) {
+ moduleLoadAttempted = true;
+ try {
+ disposableEmailModule = await import("disposable-email-domains-js");
+ } catch (e) {
+ // Silent failure
+ }
+ }
+});
+
validateWithIndicator(emailInputEl, {
schema: UserEmailSchema,
isValid: async (email: string) => {
@@ -103,6 +119,23 @@ validateWithIndicator(emailInputEl, {
warning: "Please check your email address, it may contain a typo.",
};
}
+
+ if (
+ disposableEmailModule &&
+ disposableEmailModule.isDisposableEmail !== undefined
+ ) {
+ try {
+ if (disposableEmailModule.isDisposableEmail(email)) {
+ return {
+ warning:
+ "Using a temporary email may cause issues with logging in, password resets and support. Consider using a permanent email address. Don't worry, we don't send spam.",
+ };
+ }
+ } catch (e) {
+ // Silent failure
+ }
+ }
+
return true;
},
debounceDelay: 0,
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 388991d25..6a46dd27a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -312,6 +312,9 @@ importers:
date-fns:
specifier: 3.6.0
version: 3.6.0
+ disposable-email-domains-js:
+ specifier: ^1.0.35
+ version: 1.16.0
firebase:
specifier: 12.0.0
version: 12.0.0
@@ -4627,6 +4630,9 @@ packages:
discontinuous-range@1.0.0:
resolution: {integrity: sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==}
+ disposable-email-domains-js@1.16.0:
+ resolution: {integrity: sha512-5BTVWEfUO1xeJ/jQdt+bIeOFYlgKuN5wGUtiMlkj0rqqpeO8LwiIH+7sKYvob87yMBjDKJWD8eqSSHFVM0g2pQ==}
+
docker-compose@1.2.0:
resolution: {integrity: sha512-wIU1eHk3Op7dFgELRdmOYlPYS4gP8HhH1ZmZa13QZF59y0fblzFDFmKPhyc05phCy2hze9OEvNZAsoljrs+72w==}
engines: {node: '>= 6.0.0'}
@@ -14221,6 +14227,8 @@ snapshots:
discontinuous-range@1.0.0: {}
+ disposable-email-domains-js@1.16.0: {}
+
docker-compose@1.2.0:
dependencies:
yaml: 2.5.0