How Holehe Exports Scan Results to CSV: Complete Implementation Guide

Holehe's CSV export functionality is implemented in the export_csv function in holehe/core.py, which writes OSINT scan results to a timestamped UTF‑8 CSV file when the -C/--csv flag is provided.

Holehe's CSV export functionality allows security researchers and OSINT investigators to persist email reconnaissance results for further analysis. This article examines the complete implementation details of how the megadose/holehe repository converts scan data into structured CSV output, including the data schema, file naming conventions, and programmatic usage patterns.

Where CSV Export Is Implemented

The entire CSV export pipeline lives in holehe/core.py, specifically lines 54–64 for the write logic and lines 190–194 for argument parsing. The export_csv function serves as the single entry point for all CSV operations, making the codebase maintainable and predictable.

The export_csv Function Signature and Behavior

The export_csv function accepts three parameters: the scan results list (data), the parsed arguments object (args), and the target email address. It conditionally executes only when args.csvoutput evaluates to True.


# From holehe/core.py lines 54-64

def export_csv(data, args, email):
    if args.csvoutput:
        filename = "holehe_" + str(int(time.time())) + "_" + email + "_results.csv"
        with open(filename, "w", newline='', encoding='utf-8') as f:
            fc = csv.DictWriter(f, fieldnames=data[0].keys())
            fc.writeheader()
            fc.writerows(data)
            print("All results have been exported to " + filename)
            exit()

Key implementation decisions in this function include:

  • Timestamped filenames: Uses time.time() converted to integer seconds to prevent collisions
  • Windows-compatible line endings: Opens file with newline='' to suppress extra blank lines on Windows
  • Dynamic headers: Derives column names from data[0].keys() ensuring schema flexibility
  • UTF‑8 encoding: Explicit encoding declaration for international character support

How the -C/--csv Flag Triggers Export

The command-line interface defines the CSV flag through argparse at lines 192–194 in holehe/core.py:


# From holehe/core.py lines 192-194

parser.add_argument("-C","--csv", default=False, required=False,
                    action="store_true", dest="csvoutput",
                    help="Create a CSV with the results")

When invoked, this flag sets args.csvoutput = True, which the main execution flow passes to export_csv. The action="store_true" pattern ensures the flag requires no additional value—its mere presence enables the feature.

CSV Data Schema and Field Definitions

Each row in the exported CSV represents a single module's execution result. The csv.DictWriter serializes Python dictionaries into columns, with the following standardized fields across all modules:

Field Type Description
name string Internal module identifier (e.g., twitter, gmail, adobe)
domain string Target service domain (e.g., twitter.com, gmail.com)
rateLimit boolean True if the request encountered rate limiting
exists boolean True when an account exists for the queried email
emailrecovery string or None Partially obfuscated recovery email from the service
phoneNumber string or None Partially obfuscated recovery phone number
others string or None Additional metadata such as full name, account creation date, or country

The others field demonstrates significant variance across modules—some services return rich metadata while others provide none. This is represented as None in the CSV when absent.

Command-Line Usage Examples

Basic CSV Export

Generate a CSV report from the command line:

holehe victim@example.com -C

Output:


All results have been exported to holehe_1723862123_victim@example.com_results.csv

Combined with Other Flags

The CSV flag composes with standard Holehe options:

holehe target@domain.com -C --only-used --timeout 15

This exports only services where accounts exist (exists=True), with extended timeout.

Programmatic CSV Export

For integration into larger Python workflows, instantiate the Args class and call export_csv directly:

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

async def run_email_reconnaissance(email: str):
    """Execute Holehe scan and export to CSV programmatically."""
    
    # Load all OSINT modules

    modules = import_submodules("holehe.modules")
    functions = get_functions(modules)
    
    # Collect results from each module

    results = []
    async with httpx.AsyncClient(timeout=10) as client:
        for func in functions:
            await func(email, client, results)
    
    # Configure and trigger CSV export

    class Args:
        csvoutput = True
    
    export_csv(results, Args(), email)

# Execute

trio.run(run_email_reconnaissance, "victim@example.com")

This pattern enables:

  • Custom filtering before export
  • Batch processing of multiple emails
  • Integration with async application frameworks
  • Automated reporting pipelines

File Naming and Output Location

Holehe writes CSV files to the current working directory using this pattern:


holehe_<unix_timestamp>_<email>_results.csv

Example: holehe_1723862123_victim@example.com_results.csv

The timestamp provides chronological ordering and prevents accidental overwrites when scanning the same email repeatedly. Note that special characters in email addresses are preserved in filenames, which may require quoting when processing in shell environments.

Integration with Module Result Structure

Each module in holehe/modules/ returns a dictionary conforming to the CSV schema. For example, the Adobe module constructs results like:


# Simplified from holehe/modules/software/adobe.py

return {
    "name": "adobe",
    "domain": "adobe.com",
    "rateLimit": False,
    "exists": True,
    "emailrecovery": "v***@gmail.com",
    "phoneNumber": "+1 5***12",
    "others": {"fullName": "John Doe", "createdDate": "2015-03-12"}
}

The export_csv function's use of data[0].keys() for fieldnames means modules can theoretically extend the schema, though consistency across modules ensures predictable CSV output.

Error Handling and Edge Cases

The current implementation has specific behaviors worth noting:

  • Empty results: If data is empty, data[0].keys() raises IndexError—the function assumes at least one result
  • Exit on completion: export_csv calls exit() after writing, terminating the entire process
  • No append mode: Each invocation creates a new file; no mechanism exists to append to existing CSVs

Summary

  • Primary location: holehe/core.py lines 54–64 contain the export_csv function that implements CSV export functionality
  • Trigger mechanism: The -C/--csv command-line flag, parsed at lines 192–194, activates export via args.csvoutput
  • File format: UTF‑8 encoded CSV with headers dynamically generated from result dictionary keys
  • Output filename pattern: holehe_<timestamp>_<email>_results.csv in the current working directory
  • Data schema: Seven standard fields (name, domain, rateLimit, exists, emailrecovery, phoneNumber, others) populated by each OSINT module
  • Implementation library: Python's standard csv.DictWriter with newline='' for cross-platform compatibility

Frequently Asked Questions

What information does Holehe include in CSV exports?

Holehe CSV exports contain seven fields per service checked: the module name, domain, rate limit status, account existence boolean, recovery email and phone (obfuscated), and miscellaneous metadata. These correspond exactly to the internal result dictionaries generated by each OSINT module in holehe/modules/.

How do I disable CSV export when running Holehe programmatically?

Set csvoutput = False in your arguments object. The export_csv function returns immediately without file operations when this attribute is falsy, allowing normal continuation of program execution without the exit() call.

Can I customize the CSV filename or location?

The current implementation in holehe/core.py hardcodes the filename pattern and current working directory. To customize, modify the filename assignment at line 58 or wrap export_csv with your own function that renames the file post-creation.

Why does Holehe exit after CSV export?

The exit() call at line 64 of holehe/core.py ensures clean termination after successful export in CLI contexts. For programmatic use where continuation is required, either avoid calling export_csv directly or catch SystemExit and suppress it.

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 →