Expected Function Signature for Email Scanning Modules in user-scanner
Every email-scanning module in user-scanner must expose a single asynchronous validator function named validate_<service> that takes an email string and returns a Result object.
The kaifcodec/user-scanner repository defines a strict, uniform interface for all email validation modules. This design pattern enables the core orchestrator to dynamically discover and invoke any email-checking module without service-specific logic.
Mandatory Function Signature
All email-scanning modules implement the following asynchronous signature:
async def validate_<service>(email: str) -> Result
email: str— the email address to validateResult— a return type class defined inuser_scanner/core/result.pythat encapsulates three possible states:available(),taken(...), orerror(...)
The function name follows the pattern validate_<service> where <service> is the lowercase identifier of the target platform.
Real Implementations in the Codebase
The user-scanner source code demonstrates this pattern across multiple service categories:
| Service | File Path | Function |
|---|---|---|
user_scanner/email_scan/social/instagram.py |
validate_instagram |
|
| WomanLog | user_scanner/email_scan/women_health/womanlog.py |
validate_womanlog |
| Skyscanner | user_scanner/email_scan/travel/skyscanner.py |
validate_skyscanner |
As implemented in kaifcodec/user-scanner, these validators reside under user_scanner/email_scan/<category>/<service>.py and are dynamically imported by the engine at runtime.
The Result Class Contract
The Result class in user_scanner/core/result.py provides three factory methods for consistent status reporting:
Result.available()— email not found on the serviceResult.taken(extra={...})— email registered; optionalextradict for profile metadataResult.error(message)— validation failed due to network or parsing issues
Minimal Working Example
Create a new email-scanning module by following this template:
# user_scanner/email_scan/productivity/examplemail.py
from user_scanner.core.result import Result
async def validate_examplemail(email: str) -> Result:
"""
Check if email is registered on ExampleMail service.
"""
# Perform HTTP request or API lookup
response = await fetch_email_status(email)
if response.status == 200:
return Result.taken(extra={"profile_url": response.data["url"]})
elif response.status == 404:
return Result.available()
else:
return Result.error(f"Unexpected status: {response.status}")
Invoking Validators Through the Engine
The core orchestrator in user_scanner/engine.py loads modules and executes validators without hardcoded service logic:
from user_scanner.engine import Engine
engine = Engine()
# Automatically routes to the correct validate_<service> function
result = await engine.validate_email("user@examplemail.com")
print(result.status) # "available" | "taken" | "error"
print(result.extra) # dict with additional metadata (if taken)
Architecture Benefits
The expected function signature for email scanning modules delivers three critical advantages:
- Automatic discovery — the engine scans
user_scanner/email_scan/subdirectories and imports any module matching the naming convention - Type safety — consistent
Resultreturn type eliminates brittle string parsing across the codebase - Testability — isolated async functions with no external dependencies are straightforward to mock and unit test
Summary
- All email-scanning modules must define
async def validate_<service>(email: str) -> Result - Validator functions live in
user_scanner/email_scan/<category>/<service>.py - The
Resultclass fromuser_scanner/core/result.pystandardizes return values - The engine in
user_scanner/engine.pydynamically imports and executes validators - This contract ensures uniform behavior across Instagram, Skyscanner, WomanLog, and any future services
Frequently Asked Questions
What happens if a module doesn't follow the validate_ naming convention?
The dynamic import mechanism in user_scanner/engine.py will fail to discover the function. Only modules exporting the exact validate_<service> pattern are registered as validators.
Can validate_ functions accept additional parameters beyond email?
No — the core orchestrator invokes all validators with a single positional email argument. Pass configuration through module-level constants or environment variables instead.
Is the Result class a dataclass or a custom object?
According to user_scanner/core/result.py, Result is a custom class with static factory methods. It encapsulates state internally and exposes status, extra, and boolean properties like is_available for caller inspection.
Why must email validators be asynchronous?
Network I/O dominates email validation workflows. The async design in kaifcodec/user-scanner allows the engine to run hundreds of concurrent checks across different services without thread overhead.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →