How to Use Holehe Modules Programmatically in Python

Yes, you can import Holehe as a standard Python library and invoke its async email-checking functions directly without using the CLI, leveraging the import_submodules, get_functions, and launch_module utilities exposed in holehe/core.py.

Holehe (megadose/holehe) is an open-source email reconnaissance framework that checks whether an address is registered on hundreds of websites. While the tool ships with a command-line interface, it is architected as a modular Python package that supports programmatic integration. This guide demonstrates how to use Holehe modules programmatically in Python to build custom reconnaissance workflows, automation scripts, or embedded security services.

Core Architecture and Module Structure

The programmatic interface centers on holehe/core.py, which exports three primary utilities for module discovery and execution:

  • import_submodules(package) – Recursively walks the package tree and imports every submodule under holehe/modules, returning a dictionary mapping module paths to module objects (line 37).
  • get_functions(modules, exclude_password_recovery=True) – Extracts the public async checking functions from imported modules, optionally filtering out password-recovery routines (line 50).
  • launch_module(func, email, client, out) – Executes a single module’s checking logic with an httpx.AsyncClient and accumulates results in a shared list (line 66).

Individual site checks live as separate Python files under holehe/modules/ and implement a strict async signature. For example, the Twitter checker is defined in holehe/modules/social_media/twitter.py (line 5) with the following interface:

async def twitter(email: str, client: httpx.AsyncClient, out: list) -> None:
    ...

Running a Single Module Check

To execute a specific check programmatically, load the module tree, select your target, and invoke launch_module with an HTTPX client:

import asyncio
import httpx
from holehe.core import import_submodules, launch_module

async def check_twitter(email: str):
    # Load all modules and select the Twitter checker

    modules = import_submodules("holehe.modules")
    twitter_func = modules["holehe.modules.social_media.twitter"]
    
    async with httpx.AsyncClient() as client:
        results = []
        await launch_module(twitter_func, email, client, results)
        return results[0]  # Dict containing 'name', 'domain', 'exists', etc.

if __name__ == "__main__":
    result = asyncio.run(check_twitter("example@example.com"))
    print(result)

This pattern allows you to target specific platforms without the overhead of loading the full suite.

Running a Curated Set of Modules

For scenarios requiring multiple specific checks, filter the module dictionary to build a custom execution list:

import asyncio
import httpx
from holehe.core import import_submodules, launch_module

async def run_selected(email: str, module_paths: list[str]):
    modules = import_submodules("holehe.modules")
    selected = [modules[f"holehe.modules.{path}"] for path in module_paths]
    
    async with httpx.AsyncClient() as client:
        out = []
        for func in selected:
            await launch_module(func, email, client, out)
        return out

if __name__ == "__main__":
    checks = ["social_media.twitter", "social_media.instagram"]
    results = asyncio.run(run_selected("example@example.com", checks))
    for r in results:
        print(r)

This approach provides granular control over which sites are queried while maintaining sequential execution.

Parallel Execution with Trio

Holehe natively uses the Trio async library for concurrency. To mirror the CLI’s parallel behavior programmatically, use trio.open_nursery() to spawn multiple checks simultaneously:

import trio
import httpx
from holehe.core import import_submodules, get_functions, launch_module

async def full_scan(email: str):
    modules = import_submodules("holehe.modules")
    websites = get_functions(modules)  # All available checks

    client = httpx.AsyncClient(timeout=10)
    out = []
    
    async with trio.open_nursery() as nursery:
        for site in websites:
            nursery.start_soon(launch_module, site, email, client, out)
    
    await client.aclose()
    return out

if __name__ == "__main__":
    results = trio.run(full_scan, "example@example.com")
    for r in results:
        print(r)

While asyncio works for single-module or sequentially-looped checks, trio is required to fully replicate the CLI’s parallel scanning capabilities as implemented in the source.

Supporting Files and Utilities

Beyond the core orchestration logic, several auxiliary components are relevant for programmatic use:

  • holehe/localuseragent.py – Generates randomized User-Agent strings used by every HTTP request to avoid fingerprinting.
  • holehe/__init__.py – Exposes the package version via __version__ for dependency checking in integrated applications.

Summary

  • Holehe is a standard Python package that can be imported without CLI invocation using from holehe.core import import_submodules, get_functions, launch_module.
  • Module discovery happens through import_submodules("holehe.modules"), which loads all checking logic from the holehe/modules/ directory.
  • Individual checks follow a strict async signature accepting email, httpx.AsyncClient, and a results list.
  • Execution modes range from single-module checks with asyncio to high-concurrency parallel scans using trio nurseries.
  • Integration points include the User-Agent generator in localuseragent.py and version metadata in __init__.py.

Frequently Asked Questions

Can I use Holehe with standard asyncio instead of Trio?

Yes, you can execute Holehe modules using asyncio.run() for sequential or basic concurrent execution. However, the library’s native parallel execution relies on Trio’s nursery pattern as shown in holehe/core.py. For full CLI-equivalent concurrency, Trio is recommended, though asyncio works for single-module or sequentially-looped checks.

What is the exact function signature for a Holehe module?

Every checking module must implement the following async signature: async def module_name(email: str, client: httpx.AsyncClient, out: list) -> None. The function posts the email to the target service, parses the response, and appends a result dictionary to the out list. This standardization allows launch_module to treat all site checkers as uniform callables.

How do I exclude password-recovery modules when loading functions?

Pass exclude_password_recovery=True (the default) to get_functions() in holehe/core.py. When set to true, the utility filters out modules specifically flagged for password-recovery checks, returning only standard registration-verification functions suitable for email reconnaissance workflows.

Does Holehe handle rate limiting automatically when used programmatically?

No automatic rate limiting is implemented in the core library. Each module in holehe/modules/ makes HTTP requests as fast as the event loop schedules them. When using launch_module in parallel with Trio, you may overwhelm target services. Implement your own throttling (e.g., trio.CapacityLimiter or asyncio.Semaphore) if you require rate-limited scanning in production environments.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →