Understanding the Standard Signature for a Holehe Module
Every Holehe module must implement an asynchronous function that accepts exactly three arguments—email, client, and out—and appends a standardized result dictionary to the mutable out list.
The megadose/holehe repository implements a modular email reconnaissance framework where each service-specific checker follows a strict callable contract. Understanding the standard signature for a Holehe module is essential for contributing new services or invoking existing checks programmatically. This uniformity enables the core engine in holehe/core.py to orchestrate concurrent requests across dozens of platforms using a single execution pattern.
The Asynchronous Three-Parameter Contract
Each module in the holehe/modules/ directory defines an asynchronous function with a fixed three-parameter signature. The orchestrator run_modules relies on this consistency to invoke every service checker uniformly without conditional logic for individual services.
The signature follows this exact pattern:
async def <module_name>(email, client, out):
The email Parameter
The first argument receives the target email address as a string. Modules use this value to construct probe requests that determine whether the address is registered on the specific third-party service.
The client Parameter
The second argument expects an asynchronous HTTP client, specifically an httpx.AsyncClient instance. Modules leverage this client to perform non-blocking web requests, as demonstrated in both holehe/modules/transport/blablacar.py and holehe/modules/software/office365.py.
The out Parameter
The third argument is a mutable Python list passed by reference. Rather than returning values directly via return, modules append a single dictionary describing the check outcome to this list. This callback-style pattern allows the core engine to aggregate results from hundreds of concurrent module executions efficiently.
The Standardized Result Dictionary Schema
Every module must construct a result dictionary with specific mandatory keys. The structure ensures holehe/core.py can parse outcomes consistently across disparate services with varying response formats.
Required keys include:
name— The module's internal identifier string (e.g.,blablacar)domain— The target domain being probed (e.g.,blablacar.com)method— The interaction type (register,login, orother)frequent_rate_limit— Boolean indicating if the service aggressively rate-limits requestsrateLimit— Boolean set toTrueif the current request was throttledexists— Boolean indicating whether the email is registered on the service
Optional keys provide additional context:
emailrecovery— A recovered secondary email address if exposed by the service responsephoneNumber— An associated phone number if leaked by the platformothers— A dictionary container for service-specific metadata
Practical Implementation Examples
The following examples demonstrate how the signature operates in production code from the megadose/holehe repository.
Direct Module Invocation
To call a specific module such as Blablacar directly, instantiate an HTTP client and prepare the mutable output list:
import asyncio
import httpx
from holehe.modules.transport.blablacar import blablacar
async def check_blablacar(email: str) -> dict:
async with httpx.AsyncClient() as client:
out = []
await blablacar(email, client, out)
return out[0] # Result dict for the service
result = asyncio.run(check_blablacar("example@example.com"))
print(result)
This pattern matches the implementation in holehe/modules/transport/blablacar.py, where the function appends the standardized dictionary to out without returning a value.
Core Orchestration Usage
The run_modules function in holehe/core.py automates the process across all registered modules:
import asyncio
import httpx
from holehe.core import run_modules # Core runner that iterates all modules
async def scan_email(email: str):
async with httpx.AsyncClient() as client:
results = await run_modules(email, client) # Internally calls each module
for r in results:
print(f"{r['name']}: exists={r['exists']}")
asyncio.run(scan_email("example@example.com"))
Module Discovery and Registration
The framework discovers available modules through holehe/modules/__init__.py, which registers all compliant functions. When contributing a new service, placing the async function with the standard three-parameter signature in the appropriate subdirectory ensures automatic inclusion in the scanning pipeline.
Additionally, holehe/localuseragent.py provides the ua dictionary for random User-Agent selection, which modules frequently access when configuring HTTP headers via the provided client instance.
Summary
- Every Holehe module must implement an asynchronous function accepting exactly three parameters:
email,client, andout. - The function must append a standardized result dictionary to the mutable
outlist rather than returning data directly. - Required result keys include
name,domain,method,frequent_rate_limit,rateLimit, andexists. - The
clientparameter expects anhttpx.AsyncClientinstance for asynchronous HTTP operations. - The core orchestrator in
holehe/core.pyrelies on this uniform signature to execute modules concurrently and aggregate findings.
Frequently Asked Questions
What happens if a Holehe module returns a value instead of using the out parameter?
The core engine in holehe/core.py expects results in the out list. If a module returns a value directly, the orchestrator will not capture the result, causing the output to be lost and the aggregation to fail. Always append to out and return None.
Can I use a different HTTP client instead of httpx.AsyncClient?
While the signature accepts any object as the client parameter, all existing modules in holehe/modules/ assume an httpx.AsyncClient interface. Substituting a different client requires ensuring compatibility with httpx methods like .get(), .post(), and async context managers.
Is the email parameter validated before reaching the module?
The core engine passes the email string directly without validation. Each module is responsible for sanitizing and validating the email format before making API requests, as implementation details vary by service requirements.
How does Holehe handle rate limiting across modules?
Each module sets the rateLimit boolean in its result dictionary to indicate when a request was throttled. The frequent_rate_limit key signals whether the service generally imposes strict limits, helping users interpret temporary failures versus definitive negative results.
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 →