Understanding the Email Validation Regex Pattern Used by Holehe
Holehe uses a lightweight regex pattern in holehe/core.py to validate email syntax before probing any services, accepting common valid formats while rejecting obviously malformed addresses.
The open-source OSINT tool Holehe verifies whether an email address is registered on various websites. Before making any network requests, it validates the email format using a compiled regular expression. This article breaks down the exact pattern, explains its components, and shows how to use it in your own code.
Where the Email Validation Lives
According to the megadose/holehe source code, the email validation logic resides in [holehe/core.py](https://github.com/megadose/holehe/blob/master/holehe/core.py). The implementation consists of two parts: a compiled regex constant and a helper function.
The Regex Definition (Lines 12-14)
import re
# Regular expression for validating a email
EMAIL_REGEX = re.compile(
r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$')
View source: holehe/core.py#L12-L14
The Validation Helper (Lines 15-17)
def is_valid_email(email):
return bool(EMAIL_REGEX.fullmatch(email))
View source: holehe/core.py#L15-L17
Breaking Down the Regex Pattern
The Holehe email validation regex follows a practical rather than RFC-compliant approach. Here's how each component works:
| Segment | Pattern | Purpose |
|---|---|---|
| Start anchor | ^ |
Ensures match begins at string start |
| Local part | [a-zA-Z0-9_.+-]+ |
Username before @; allows letters, digits, underscores, dots, plus signs, and hyphens |
| Separator | @ |
Literal at-sign |
| Domain name | [a-zA-Z0-9-]+ |
Domain labels; allows letters, digits, and hyphens |
| Dot separator | \. |
Literal period before TLD |
| TLD/subdomains | [a-zA-Z0-9-.]+ |
Top-level domain and optional subdomains; allows multiple dots for domains like co.uk |
| End anchor | $ |
Ensures match reaches string end |
What This Pattern Accepts and Rejects
Accepted formats:
user@example.comfirst.last@sub.domain.co.ukuser+tag@domain.orguser-name@domain-name.com
Rejected formats:
user@domain(missing TLD)user name@domain.com(space in local part)user@domain..com(consecutive dots pass but fail in practice)@domain.com(empty local part)user@.com(empty domain label)
Using the Validation in Your Code
Direct Import and Usage
from holehe.core import is_valid_email
# Valid emails
print(is_valid_email("alice@example.com")) # True
print(is_valid_email("bob.smith+tag@sub.co.uk")) # True
# Invalid emails
print(is_valid_email("charlie@invalid")) # False (no TLD)
print(is_valid_email("dave @domain.com")) # False (space)
print(is_valid_email("eve@domain..com")) # True (regex accepts, but malformed)
Replicating the Pattern Manually
import re
# Same pattern as defined in holehe/core.py
EMAIL_REGEX = re.compile(
r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$')
def custom_validate(email):
"""Returns match object or None; use bool() for True/False"""
return EMAIL_REGEX.fullmatch(email)
test_emails = [
"valid@example.com",
"also-valid+tag@sub.domain.org",
"invalid@domain",
"no-at-sign.com",
"spaces not@allowed.com"
]
for email in test_emails:
match = custom_validate(email)
status = "valid" if match else "invalid"
print(f"{email:<25} → {status}")
How Holehe Uses Email Validation
The validation runs immediately when processing command-line arguments. Here's the typical flow:
# Simplified representation of Holehe's internal flow
async def main(email, **options):
# Step 1: Validate format before any network activity
if not is_valid_email(email):
print("Error: Invalid email format")
return
# Step 2: Proceed with service-specific checks only if valid
results = await run_modules(email, options)
return results
This early-exit pattern prevents wasting API calls and rate limits on malformed inputs.
Limitations and Design Rationale
The Holehe email validation regex is intentionally permissive. It prioritizes:
- Speed: Simple regex evaluation is faster than full RFC 5322 parsing
- Practical coverage: Catches obvious typos while accepting most real-world addresses
- Tool scope: Holehe probes registration status, not mailbox deliverability
For production systems requiring strict validation, consider supplementing with:
- DNS MX record verification (confirm domain accepts mail)
- SMTP handshake testing (verify mailbox exists)
- RFC 5322-compliant libraries like
email-validatorfor Python
Summary
- The Holehe email validation regex is defined in
holehe/core.pyat lines 12-14 asEMAIL_REGEX - The
is_valid_email()function at lines 15-17 wrapsfullmatch()for boolean returns - The pattern accepts letters, digits, and limited special characters in local and domain parts
- This validation runs before any network requests to filter malformed inputs efficiently
Frequently Asked Questions
What characters are allowed in the local part of an email according to Holehe's regex?
Holehe allows letters (a-z, A-Z), digits (0-9), underscores, dots, plus signs, and hyphens in the local part (before the @). The pattern [a-zA-Z0-9_.+-]+ requires at least one such character.
Does Holehe's regex validate that an email actually exists?
No. The regex only checks syntactic format. It cannot verify DNS records, SMTP connectivity, or whether a mailbox is active. Holehe uses this lightweight check to reject obvious garbage before making HTTP requests to various services.
Why doesn't Holehe use a more complex RFC 5322-compliant regex?
RFC 5322 permits quoted strings, comments, and other edge cases rarely seen in practice. Holehe's maintainer chose a simpler pattern that covers 99%+ of real-world addresses while remaining readable and fast. Complex regexes for email validation often become unmaintainable and still fail on edge cases.
Can I use is_valid_email() in my own Python projects?
Yes. Import it directly from the module: from holehe.core import is_valid_email. Note that Holehe is released under the GNU General Public License v3.0, so derivative works must comply with GPL terms if you distribute modified versions.
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 →