What Information Is Passed to an Async Module Function in Holehe?

Every async module function in Holehe receives three arguments: the target email string, a shared aiohttp.ClientSession instance, and a mutable results list for collecting output.

Holehe is an open-source email investigation framework developed by megadose that verifies address existence across hundreds of online services. Understanding what information is passed to an async module function in Holehe is critical for developers extending the tool or analyzing its enumeration capabilities. The codebase enforces a strict uniform interface across all service modules, enabling the core runner to orchestrate parallel checks while maintaining consistent data contracts.

The Standard Three-Parameter Signature

Every service-specific checker in Holehe implements an identical asynchronous function signature. You can see this pattern in holehe/modules/social_media/twitter.py and holehe/modules/software/office365.py:

async def <service_name>(email, client, out):
    ...

This consistent interface allows the orchestration logic in holehe/core.py to invoke dozens of modules concurrently without requiring service-specific handling logic.

The email Parameter

The email parameter is a Python string containing the address being investigated. Modules use this value to construct registration validation requests against their target platforms. For instance, when checking Twitter, the module passes this email to Twitter's registration availability endpoints to determine if an account exists.

The client Parameter

The client parameter is an aiohttp.ClientSession instance created once in the core runner and shared across all modules. This asynchronous HTTP client enables non-blocking web requests throughout the checking process. The session configuration, including user-agent strings defined in holehe/localuseragent.py, is applied globally to maintain consistent request signatures and connection pooling across hundreds of simultaneous checks.

The out Parameter

The out parameter is a mutable Python list that serves as a concurrent result collector. Each module appends a standardized dictionary to this shared list rather than returning values directly. This design pattern eliminates the need for complex synchronization primitives while allowing asyncio.gather() to aggregate results from all parallel checks into a single collection.

The Result Dictionary Structure

Every module appends a dictionary with specific schema fields to the out list. As implemented in holehe/modules/social_media/twitter.py, the structure contains:

  • name: Human-readable service identifier (e.g., "twitter")
  • domain: The service domain (e.g., "twitter.com")
  • method: Verification method employed (typically "register")
  • frequent_rate_limit: Boolean indicating whether the service applies strict rate-limiting policies
  • rateLimit: Boolean set to True if the current request encountered a rate limit
  • exists: Boolean indicating whether the email is registered on the service
  • emailrecovery, phoneNumber, others: Optional metadata fields usually defaulting to None

Implementation Examples from the Source Code

Calling a Module Directly

You can invoke individual modules for testing or targeted service checks:

import aiohttp
from holehe.modules.social_media import twitter

async def run_one_check():
    async with aiohttp.ClientSession() as client:
        results = []
        await twitter("example@example.com", client, results)
        print(results)
        # Output: [{'name': 'twitter', 'domain': 'twitter.com', ...}]

Core Orchestration Pattern

The holehe/core.py file demonstrates how the framework leverages the uniform signature to execute parallel checks:

import asyncio
import aiohttp
from holehe.modules import social_media, software

async def run_all(email):
    async with aiohttp.ClientSession() as client:
        out = []
        # Collect all async functions from module packages

        tasks = [
            func(email, client, out)
            for func in [
                social_media.twitter.twitter,
                social_media.facebook.facebook,
                software.office365.office365,
                # ... additional modules

            ]
        ]
        await asyncio.gather(*tasks)
        return out

This pattern creates coroutine tasks for each module function, passing identical argument positions to each, then executes them concurrently using asyncio.gather().

Key Source Files in the Repository

The implementation of this async interface spans several critical files in the megadose/holehe repository:

Summary

  • Every async module function in Holehe receives exactly three arguments: an email string, an aiohttp.ClientSession, and a mutable results list.
  • The email parameter provides the target address for verification against specific services.
  • The client parameter enables shared, non-blocking HTTP requests with consistent configuration across all parallel checks.
  • The out parameter acts as a concurrent result collector, with modules appending standardized dictionaries containing existence status, rate limit flags, and service metadata.
  • This uniform design allows holehe/core.py to orchestrate hundreds of parallel service checks efficiently without module-specific invocation logic.

Frequently Asked Questions

What is the exact function signature required for Holehe async modules?

Every service module must implement async def <service_name>(email, client, out). This three-parameter signature is enforced across all files in the holehe/modules/ directory, from social media checkers to enterprise software validators. The core runner in holehe/core.py depends on this consistency to invoke modules generically using positional arguments.

Why does Holehe pass the HTTP client as a parameter rather than creating it inside each module?

Passing the aiohttp.ClientSession as the client parameter allows the core runner to maintain a single session with shared connection pooling and configuration. This approach, defined in holehe/core.py, reduces TCP connection overhead and ensures consistent request headers—including the user-agent from holehe/localuseragent.py—across all simultaneous checks performed by the async modules.

What happens if a module fails to append to the out list?

If a module does not append its result dictionary to the out list, that service check produces no output in the final aggregation. The mutable list design requires explicit appends; otherwise, the check effectively disappears from results. The standard pattern shown in holehe/modules/social_media/twitter.py ensures every code path appends a result, including error states and rate limit detections.

Can custom modules use different parameter names or accept additional arguments?

No, custom modules must adhere strictly to the (email, client, out) signature. The core orchestration logic in holehe/core.py discovers and calls modules using positional arguments based on this contract. Adding extra parameters or altering names would break the generic invocation pattern used by asyncio.gather() in the main execution loop, causing runtime errors during parallel processing.

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 →