How to Embed Holehe Functionality into Your Python Project: A Complete Integration Guide
You can embed Holehe into any Python project by importing its asynchronous site modules, passing an httpx.AsyncClient and an empty result list, then awaiting the check functions for direct OSINT email verification.
Holehe is a lightweight, asynchronous OSINT library by megadose/holehe that probes over 120 online services to determine whether an email address is linked to existing accounts. Because the tool is built as a collection of pure asynchronous functions rather than a monolithic CLI, you can embed Holehe functionality into your Python project to build custom email investigation pipelines, automate reconnaissance workflows, or integrate account existence checks into larger security tools.
Understanding Holehe’s Architecture
Dynamic Module Loading System
The library uses a dynamic module loader to discover and import site-specific checkers at runtime. In holehe/core.py, the import_submodules function (lines 37-47) walks the holehe.modules package, automatically discovering every site-specific script without manual registration. This design allows the library to support new services simply by adding new files to the modules directory.
The Standardized Site Interface
Each site module implements a consistent asynchronous interface defined as async def <site>(email, client, out). As seen in holehe/modules/social_media/twitter.py (lines 5-37), the function receives three parameters: the target email string, an httpx.AsyncClient instance for HTTP communication, and a shared list (out) that collects results. The function appends a dictionary with a fixed schema containing name, domain, rateLimit, exists, emailrecovery, phoneNumber, and others. This standardization means every module follows the same contract regardless of which service it probes.
Step-by-Step Integration Guide
Installation and Dependencies
First, install Holehe via PyPI to access the core library and all site modules:
pip install holehe
The library depends on httpx for asynchronous HTTP requests and trio for structured concurrency, though you can substitute trio with standard asyncio if preferred.
Basic Single-Module Execution
To embed Holehe functionality into your Python project for checking a single service, import the specific module, create an httpx.AsyncClient, and await the check function:
import trio
import httpx
from holehe.modules.social_media.twitter import twitter
async def check_single_email():
email = "test@example.com"
out = [] # shared list for results
client = httpx.AsyncClient(timeout=10)
await twitter(email, client, out)
# Process results
for result in out:
if result["exists"]:
print(f"[+] Account found on {result['domain']}")
await client.aclose()
trio.run(check_single_email)
This pattern works for any module in the holehe.modules package, from social media platforms to developer tools.
Orchestrating Multiple Checks
For batch processing, instantiate a single httpx.AsyncClient to share connection pools across multiple services, then run several modules against the same email:
import trio
import httpx
from holehe.modules.social_media.snapchat import snapchat
from holehe.modules.social_media.twitter import twitter
async def check_multiple_services():
email = "test@example.com"
out = []
client = httpx.AsyncClient(timeout=10)
# Run multiple checks
await snapchat(email, client, out)
await twitter(email, client, out)
# Filter results
found_accounts = [r for r in out if r["exists"]]
print(f"Found {len(found_accounts)} registered services")
await client.aclose()
trio.run(check_multiple_services)
Processing Results Programmatically
Each module populates the shared out list with dictionaries containing standardized keys. According to holehe/core.py (lines 6-52), the result aggregation system expects these fields:
- name: The service name (e.g., "Twitter")
- domain: The service domain (e.g., "twitter.com")
- rateLimit: Boolean indicating if the service throttled the request
- exists: Boolean indicating if the email is registered
- emailrecovery: Partial email recovery information if exposed
- phoneNumber: Phone number fragments if exposed
- others: Additional metadata
You can filter results based on the exists field to identify where the target email has active accounts, or check rateLimit to implement retry logic with exponential backoff.
Advanced Usage Patterns
Using the Built-in Launcher
For automated batch analysis, reuse Holehe's own orchestration logic through the launch_module wrapper in holehe/core.py (lines 166-176). This function handles exception trapping and module execution:
import trio
import httpx
from holehe.core import import_submodules, get_functions, launch_module
async def run_full_recon(email):
client = httpx.AsyncClient()
modules = import_submodules("holehe.modules")
sites = get_functions(modules) # all available site checkers
out = []
async with trio.open_nursery() as n:
for site in sites:
n.start_soon(launch_module, site, email, client, out)
await client.aclose()
return out
# Run complete OSINT check
results = trio.run(lambda: run_full_recon("target@example.com"))
exists_only = [r for r in results if r["exists"]]
Handling Rate Limits and Errors
The result dictionary's rateLimit key indicates when a service has throttled requests. When embedding Holehe into production systems, implement IP rotation or request spacing when rateLimit returns True. The others field often contains HTTP status codes or error messages that help distinguish between connection failures, CAPTCHA triggers, and definitive "email not found" responses.
Summary
- Holehe uses a dynamic module loading system (
import_submodulesinholehe/core.py) to discover site checkers automatically. - Every module follows the standardized interface
async def <site>(email, client, out)and returns results to a shared list. - You must provide an
httpx.AsyncClientto each module for connection pooling and timeout management. - Results follow a fixed schema with keys including
exists,rateLimit, anddomainfor consistent data processing. - Use
launch_modulefromholehe/core.pyto leverage built-in exception handling when running checks at scale.
Frequently Asked Questions
Can I use asyncio instead of Trio to run Holehe modules?
Yes. While the upstream CLI uses Trio for structured concurrency, the modules are pure async def functions compatible with any asyncio-compatible event loop. Simply replace trio.run() with asyncio.run() or use await within your existing async application.
What data structure does each Holehe module return?
Each module appends a dictionary to the provided out list with seven fixed keys: name, domain, rateLimit, exists, emailrecovery, phoneNumber, and others. This schema is consistent across all 120+ services, allowing uniform result processing regardless of which site module you invoke.
How do I run all available Holehe modules at once?
Import import_submodules and get_functions from holehe/core.py to dynamically load all site modules, then use launch_module with a Trio nursery (or asyncio tasks) to execute them concurrently. This approach mirrors the tool's own CLI behavior while giving you programmatic access to the aggregated results.
Is it safe to reuse the same httpx.AsyncClient across multiple checks?
Yes. In fact, reusing the httpx.AsyncClient is recommended because it maintains connection pooling, keeps TCP connections alive, and respects shared timeout and header configurations across all Holehe modules. Instantiate one client at the start of your workflow and pass it to every module before closing it at the end.
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 →