Holehe Module Output Schema: How `emailrecovery` and `phoneNumber` Work
The module output schema in holehe is a standardized dictionary with nine fields including emailrecovery and phoneNumber, which contain recovery email addresses and masked phone numbers returned by target services.
Holehe is an open-source OSINT tool that checks whether an email address is registered on hundreds of platforms. Each service check runs as an independent module that returns results in a uniform format. Understanding this schema is essential for anyone building custom modules or parsing holehe output programmatically.
The Standard Output Schema Structure
Every module in holehe appends a dictionary to the shared result list (out) with these exact keys:
| Key | Type | Purpose |
|---|---|---|
name |
str |
Internal module identifier (e.g., "twitter") |
domain |
str |
Human-readable service domain (e.g., "twitter.com") |
method |
str |
Test method used: "register" or "login" |
frequent_rate_limit |
bool |
Whether the service has known rate-limiting behavior |
rateLimit |
bool |
True if the current request hit a rate limit |
exists |
bool |
True if the email is registered on the service |
emailrecovery |
str or None |
Recovery email returned by the service (often masked) |
phoneNumber |
str or None |
Phone number returned by the service (often masked) |
others |
dict |
Optional free-form container for additional extracted data |
This schema is enforced through the consuming code in holehe/core.py, specifically in the print_result and launch_module functions. The uniformity allows the core engine to process results from any service identically.
How emailrecovery and phoneNumber Get Populated
The emailrecovery and phoneNumber fields are service-dependent. Most modules initialize both as None and only overwrite them when the target API explicitly returns recovery information.
Example: Adobe Module with Recovery Data
In holehe/modules/software/adobe.py, the module extracts secondary email and security phone information when available:
# Simplified excerpt from holehe/modules/software/adobe.py
async def adobe(email, client, out):
# ... HTTP request logic ...
# When Adobe returns recovery information:
out.append({
"name": "adobe",
"domain": "adobe.com",
"method": "register",
"frequent_rate_limit": False,
"rateLimit": False,
"exists": True,
"emailrecovery": "j***@example.com", # Masked recovery email
"phoneNumber": "+1 ***-***-1234", # Masked phone
"others": {}
})
Example: Twitter Module Without Recovery Data
By contrast, holehe/modules/social_media/twitter.py only checks for existence and leaves recovery fields empty:
# Simplified pattern from holehe/modules/social_media/twitter.py
out.append({
"name": "twitter",
"domain": "twitter.com",
"method": "register",
"frequent_rate_limit": True,
"rateLimit": False,
"exists": True, # Email found
"emailrecovery": None,
"phoneNumber": None,
"others": {}
})
Console Output Formatting in print_result
The print_result function in holehe/core.py concatenates emailrecovery and phoneNumber when present:
# From holehe/core.py print_result function
toprint = f"[+] {results['name']} {email}"
if results["emailrecovery"] is not None:
toprint += " " + results["emailrecovery"]
if results["phoneNumber"] is not None:
toprint += " / " + results["phoneNumber"]
This produces console output like:
[+] adobe target@example.com j***@example.com / +1 ***-***-1234
[+] twitter target@example.com
Notice how Twitter shows no recovery data while Adobe displays both fields.
Building a Custom Module with the Schema
When creating your own holehe module, follow this pattern exactly:
# Minimal custom module template
async def my_service(email, client, out):
"""
Check if email exists on my-service.com
"""
# Perform HTTP checks with the provided client
# ...
# Always append the full schema dictionary
out.append({
"name": "my_service", # Function name
"domain": "my-service.com", # Service domain
"method": "register", # Detection method used
"frequent_rate_limit": False, # Known behavior
"rateLimit": False, # This request status
"exists": True, # Detection result
"emailrecovery": None, # Or extracted value
"phoneNumber": None, # Or extracted value
"others": { # Optional extra data
"username": "extracted_user"
}
})
Key Source Files Defining the Schema
| File | Role |
|---|---|
holehe/core.py |
Defines consumption logic in print_result and launch_module; documents schema through function contracts |
holehe/modules/software/adobe.py |
Reference implementation showing emailrecovery and phoneNumber population |
holehe/modules/social_media/twitter.py |
Reference implementation with null recovery fields |
holehe/modules/__init__.py |
Module discovery and loading for the core engine |
Summary
- Holehe uses a strict 9-field output schema that every module must follow.
emailrecoverycontains recovery email addresses (often masked) when services expose them.phoneNumbercontains phone numbers (often masked) when services expose them.- Both fields default to
Noneand are omitted from console output when absent. - The schema is enforced by
holehe/core.py, not by per-module validation. - Adobe serves as the canonical example of a module extracting recovery data.
Frequently Asked Questions
What happens if a module doesn't include all nine fields?
The print_result function in holehe/core.py expects all keys; omitting fields causes KeyError exceptions. All modules in the repository follow the complete schema even when returning None for unused fields.
Why do some services show masked emails while others show full addresses?
Masking is performed by the target service's API, not by holehe. The emailrecovery field stores whatever string the service returns—some mask partially (Adobe), some return full addresses, and most return nothing at all.
Can modules add arbitrary fields beyond the standard schema?
No—the core engine only recognizes the nine defined keys. However, the others dictionary accepts any additional key-value pairs for extended data extraction, and these display in console output.
How do I check if a module supports phone number extraction?
Inspect the module source in holehe/modules/ or run holehe and check output. Modules populating phoneNumber explicitly assign it in their out.append() call rather than leaving it as None.
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 →