Required Signature for a Holehe Site Module: Complete Implementation Guide
Every Holehe site module must expose a single asynchronous function accepting three parameters—email, client, and out—and return None while appending a standardized result dictionary to the mutable out list.
Holehe is an open-source email OSINT framework that verifies account existence across hundreds of platforms. To extend its coverage, developers create site modules that plug into the core engine via a strict asynchronous interface. Understanding the required signature for a Holehe site module ensures your code integrates seamlessly with the tool's concurrent execution and result aggregation systems.
The Standardized Asynchronous Signature
Each module in the holehe/modules/ directory must implement a function conforming to this exact signature:
async def <module_name>(email: str, client: httpx.AsyncClient, out: list) -> None
This signature enables the orchestration logic in holehe/core.py to uniformly discover and invoke modules using reflection. The core's launch_module function calls each module with await module(email, client, out), passing a shared HTTP client and a mutable list for result collection.
Parameter Breakdown
email(str): The target email address to investigate.client(httpx.AsyncClient): A pre-configured asynchronous HTTP client supplied by the core. Modules must use this instance for all requests to ensure proper timeout handling and connection pooling.out(list): A mutable list passed by reference. The module must append a result dictionary to this list; the core aggregates these entries after all modules complete.
Required Result Dictionary Structure
When appending to out, modules must provide a dictionary containing these mandatory keys:
name: Internal identifier (typically matches the function name)domain: Target domain (e.g.,"twitter.com")method: Verification approach ("register"or"login")frequent_rate_limit: Boolean indicating if the service aggressively rate-limitsrateLimit: Boolean indicating if the current request encountered rate limitingexists: Boolean indicating if the email is registered on the serviceemailrecovery: Optional string containing a password-recovery hintphoneNumber: Optional string with a discovered phone numberothers: Optional dictionary containing additional metadata (e.g., full name, account creation date)
Real-World Implementation Example
The Twitter module at holehe/modules/social_media/twitter.py demonstrates the canonical implementation:
from holehe.core import *
from holehe.localuseragent import *
async def twitter(email, client, out):
name = "twitter"
domain = "twitter.com"
method = "register"
frequent_rate_limit = False
try:
req = await client.get(
"https://api.twitter.com/i/users/email_available.json",
params={"email": email})
if req.json()["taken"]:
out.append({
"name": name,
"domain": domain,
"method": method,
"frequent_rate_limit": frequent_rate_limit,
"rateLimit": False,
"exists": True,
"emailrecovery": None,
"phoneNumber": None,
"others": None,
})
except Exception:
raise
The function never returns a value; it exclusively mutates out via append. The core's launch_module wrapper catches exceptions and injects standardized error entries, so modules can propagate errors without handling aggregation logic.
Creating a Minimal Custom Module
For a fictional service, implement the same pattern:
# File: holehe/modules/social_media/example.py
from holehe.core import *
from holehe.localuseragent import *
async def example(email, client, out):
name = "example"
domain = "example.com"
method = "register"
frequent_rate_limit = False
resp = await client.head(f"https://api.example.com/users/{email}")
exists = resp.status_code == 200
out.append({
"name": name,
"domain": domain,
"method": method,
"frequent_rate_limit": frequent_rate_limit,
"rateLimit": False,
"exists": exists,
"emailrecovery": None,
"phoneNumber": None,
"others": None,
})
How the Core Engine Invokes Modules
The holehe/core.py file orchestrates execution through several key mechanisms:
- Discovery: The
import_submodulesfunction dynamically imports all Python files within theholehe/modulespackage. - Extraction:
get_functionsretrieves callable objects from imported modules using introspection. - Invocation:
launch_moduleawaits each discovered function with the standard signature, ensuring the sharedhttpx.AsyncClientand result list propagate correctly. - Concurrency: The framework uses Trio nurseries to execute modules concurrently. The shared
outlist enables thread-safe result collection without complex synchronization.
This architecture explains why strict adherence to the signature is mandatory—any deviation breaks the reflection-based invocation chain in launch_module.
Summary
- Site modules must expose an async function accepting
email,client, andoutparameters exactly as typed. - Functions must return
Noneand append standardized result dictionaries to theoutlist. - Required dictionary keys include
name,domain,method,exists,rateLimit, andfrequent_rate_limit, with optional fields foremailrecovery,phoneNumber, andothers. - The core engine in
holehe/core.pyhandles module discovery, concurrent execution via Trio, and automatic error handling. - Reference
holehe/modules/social_media/twitter.pyfor production-ready implementation patterns.
Frequently Asked Questions
What happens if my module doesn't append to the out list?
The module produces no visible output. Because launch_module in holehe/core.py does not inspect return values, failing to append to out effectively silences the module—the core will not report results for that service.
Can I use a different HTTP client instead of the provided httpx.AsyncClient?
No. Modules must use the injected client parameter to ensure consistent timeout configurations, connection pooling, and integration with the core's rate-limiting instrumentation. Using an independent client bypasses these protections and may trigger IP bans.
How does the core handle exceptions in site modules?
The launch_module function wraps each invocation in a try-except block. When a module raises an exception, the core automatically appends an error entry to the out list and continues execution. This design allows other modules to proceed while preserving diagnostic information for the failed check.
Is the method field limited to specific values?
While the core accepts any string, convention restricts this field to "register" for registration page probes and "login" for authentication endpoint checks. These standardized values help users interpret whether the verification used signup flows or login attempts.
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 →