Summary
Block self-serve sign-ups (email/password, magic link, OAuth) that use disposable / trash email domains, using a maintained community list plus a small custom list for domains we observe on Rhesis that aren't upstream yet.
Problem / Opportunity
Disposable-email domains are used to create throwaway accounts that spam or abuse the platform. We currently only validate email format + MX deliverability, so temporary inboxes (mailinator.com, 10minutemail.com, etc.) pass. We've also seen recent sign-ups from trash domains not yet covered by public lists.
Users & Use Cases
- Persona: Rhesis platform / operations.
- Use case: Prevent abusive throwaway sign-ups while letting legitimate users register.
Proposal
-
Source list: disposable-email-domains PyPI package (MIT, exposes blocklist as a set, ~daily updates). Library repo: https://github.com/disposable-email-domains/python-disposable-email-domains (packaged form of https://github.com/disposable-email-domains/disposable-email-domains). Add via uv add disposable-email-domains in apps/backend.
-
Custom list in repo: app/auth/disposable_domains_custom.txt, loaded with Path(__file__).parent (same pattern as bulk_defaults.json) and merged with the PyPI set. This is where we add domains the public list is missing.
-
Optional env override AUTH_DISPOSABLE_EMAIL_EXTRA_DOMAINS (comma-separated) for blocking a domain urgently without a deploy.
-
Toggle AUTH_BLOCK_DISPOSABLE_EMAILS (default true) on AuthSettings.
-
Enforcement: extend validate_and_normalize_email() with reject_disposable (progressive subdomain stripping), applied to self-serve sign-up paths only:
EmailProvider.register()
request_magic_link() (currently bypasses domain validation)
- OAuth new-user branch in
find_or_create_user_from_auth()
Admin invites (POST /users/) are NOT blocked.
Non-Goals / Out of Scope
- No blocking of existing users or admin-invited users.
- No UI for managing the list in this iteration (repo file + env override only).
Acceptance Criteria (testable)
Additional Context
Discussion: keep the list in the repo / use a library rather than a hardcoded env var.
Reviewer: @akwasigroch (proposed the library/repo-list approach).
Summary
Block self-serve sign-ups (email/password, magic link, OAuth) that use disposable / trash email domains, using a maintained community list plus a small custom list for domains we observe on Rhesis that aren't upstream yet.
Problem / Opportunity
Disposable-email domains are used to create throwaway accounts that spam or abuse the platform. We currently only validate email format + MX deliverability, so temporary inboxes (mailinator.com, 10minutemail.com, etc.) pass. We've also seen recent sign-ups from trash domains not yet covered by public lists.
Users & Use Cases
Proposal
Source list:
disposable-email-domainsPyPI package (MIT, exposesblocklistas aset, ~daily updates). Library repo: https://github.com/disposable-email-domains/python-disposable-email-domains (packaged form of https://github.com/disposable-email-domains/disposable-email-domains). Add viauv add disposable-email-domainsinapps/backend.Custom list in repo:
app/auth/disposable_domains_custom.txt, loaded withPath(__file__).parent(same pattern asbulk_defaults.json) and merged with the PyPI set. This is where we add domains the public list is missing.Optional env override
AUTH_DISPOSABLE_EMAIL_EXTRA_DOMAINS(comma-separated) for blocking a domain urgently without a deploy.Toggle
AUTH_BLOCK_DISPOSABLE_EMAILS(default true) onAuthSettings.Enforcement: extend
validate_and_normalize_email()withreject_disposable(progressive subdomain stripping), applied to self-serve sign-up paths only:EmailProvider.register()request_magic_link()(currently bypasses domain validation)find_or_create_user_from_auth()Admin invites (
POST /users/) are NOT blocked.Non-Goals / Out of Scope
Acceptance Criteria (testable)
AUTH_BLOCK_DISPOSABLE_EMAILS=falsefully disables the check.Additional Context
Discussion: keep the list in the repo / use a library rather than a hardcoded env var.
Reviewer: @akwasigroch (proposed the library/repo-list approach).