How Holehe Checks for Email Existence on Websites: Architecture and Implementation
Holehe verifies email registration status across hundreds of platforms by dynamically loading site-specific asynchronous checker modules and executing them concurrently using Trio with a shared HTTP client.
The open-source tool megadose/holehe automates the process of determining whether an email address is already registered on over 250 websites. Unlike simple DNS lookups, Holehe performs live checks against each platform's registration endpoints by orchestrating a modular Python architecture that combines dynamic module loading with high-performance asynchronous I/O.
Dynamic Module Loading System
Holehe begins its verification process by discovering and importing site-specific checker functions from the holehe.modules package tree.
The import_submodules("holehe.modules") function in holehe/core.py:37-48 recursively walks the module directory, importing every Python file that implements a site-specific async function. Following the import phase, get_functions() (defined in holehe/core.py:50-63) extracts callable objects from these modules and stores them in a list called websites.
This architecture allows the tool to support over 250 distinct platforms without hardcoding individual site logic in the main execution loop. Each module adheres to a standardized signature: async def <site>(email, client, out).
Concurrent Execution with Trio and HTTPX
Once modules are loaded, Holehe initializes a single httpx.AsyncClient instance with configurable timeout settings (holehe/core.py:11-14). This shared client enables connection pooling and TLS session reuse across all concurrent requests, significantly improving performance when checking hundreds of sites.
The execution engine leverages Trio for structured concurrency. In holehe/core.py:18-30, the code opens a nursery that spawns a launch_module task for every site in the websites list. Each task receives the target email address, the shared HTTP client, and a thread-safe results list (out).
# Conceptual flow from holehe/core.py
async with trio.open_nursery() as nursery:
for website in websites:
nursery.start_soon(launch_module, website, email, client, out)
Site-Specific Verification Logic
Every checker module implements the same three-state logic to determine email existence. The function signature async def <site>(email, client, out) requires each module to send HTTP requests, parse responses, and append a dictionary with one of three outcomes to the shared out list:
- exists = True: The email is already registered on the service
- exists = False: The email is not found or available for registration
- rateLimit = True: The service has throttled or blocked the request
Instagram Implementation Example
The Instagram checker in holehe/modules/social_media/instagram.py demonstrates this pattern:
- CSRF Token Acquisition: Sends a GET request to retrieve a hidden CSRF token from the signup page
- Registration Attempt: POSTs to
accounts/web_create_ajax/attempt/with a random username and the target email - Response Parsing: Inspects the JSON response for
"email_is_taken"or"email_sharing_limit"indicators - Result Classification: Sets
exists=Trueif registration is blocked due to email reuse, orrateLimit=Trueif the response indicates throttling
Other modules follow identical architectural patterns while customizing request URLs, headers (often rotating User-Agents from holehe/localuseragent.py), and parsing logic to match each service's API or web form behavior.
Result Aggregation and Output
After all nursery tasks complete, Holehe processes the out list containing results from every module. The presentation layer in holehe/core.py sorts these results and displays them with color-coded status symbols:
[+]Green: Email exists on the platform[-]Red: Email not found (available)[x]Yellow: Rate limited or blocked[!]Error: Network or parsing failure
Users can optionally export results to CSV using the --csv flag, or filter output with --only-used to display only registered accounts.
Practical Usage Examples
Command-Line Interface
Run Holehe from the terminal to check a single email against all supported sites:
# Check email against all 250+ modules
holehe email@example.com
# Show only sites where email is registered
holehe email@example.com --only-used
# Export results to CSV file
holehe email@example.com --csv
Programmatic Integration
Import Holehe's core functions to embed email verification in Python applications:
import asyncio
import httpx
from holehe.core import import_submodules, get_functions, launch_module
async def verify_email(email: str):
# Load all checker modules
modules = import_submodules("holehe.modules")
websites = get_functions(modules)
# Initialize shared async client
client = httpx.AsyncClient(timeout=10)
results = []
# Execute checks with concurrency limiting
async with asyncio.Semaphore(20):
for site in websites:
await launch_module(site, email, client, results)
await client.aclose()
return results
# Usage
if __name__ == "__main__":
email = "test@example.com"
output = asyncio.run(verify_email(email))
for result in output:
print(f"{result['domain']}: {result['exists']}")
Summary
- Holehe checks email existence by dynamically importing 250+ site-specific modules from
holehe.modulesusingimport_submodules()andget_functions()incore.py - It executes checks concurrently using Trio nurseries and a shared
httpx.AsyncClientfor efficient connection pooling - Each module follows a standardized async signature returning
exists,exists=False, orrateLimitstatus based on HTTP response parsing - The Instagram checker exemplifies the pattern: CSRF token retrieval, POST to registration endpoint, and JSON response inspection
- Results are aggregated in a thread-safe list and displayed with color-coded symbols (
[+],[-],[x]) or exported to CSV
Frequently Asked Questions
How does Holehe handle rate limiting from websites?
Each site-specific module detects throttling independently by inspecting HTTP status codes, error messages, or response headers. When a service returns rate-limit indicators, the module appends rateLimit=True to the results list rather than exists=True or exists=False. Holehe displays these instances with a [x] symbol, allowing users to distinguish between "email not found" and "check blocked by service."
Can Holehe check custom or internal websites?
While Holehe ships with 250+ pre-built checkers in holehe/modules/, the modular architecture supports extensions. Developers can add custom checks by creating new Python files in the modules directory that implement the async def <site>(email, client, out) signature, handling their specific target's CSRF tokens, form submissions, and response parsing patterns.
Is Holehe undetectable when checking email existence?
Holehe attempts to mimic legitimate browser traffic by rotating User-Agent strings from holehe/localuseragent.py and handling cookies like real web clients. However, sophisticated platforms may still detect automated requests through behavioral analysis or CAPTCHA challenges. The tool does not bypass advanced bot detection, and heavy usage may trigger IP-based rate limiting.
What Python libraries does Holehe require for async operations?
Holehe relies on Trio for structured concurrency and task management, and HTTPX for asynchronous HTTP/1.1 and HTTP/2 requests. These dependencies enable the tool to maintain hundreds of simultaneous connections while sharing TLS sessions and connection pools across all site checks.
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 →