Cookbook/Blocking Email Addresses in Prompts with Claude Code Hooks
general
5 min

Blocking Email Addresses in Prompts with Claude Code Hooks

Blocking Email Addresses in Prompts with Claude Code Hooks

What You'll Learn

Create a hook that automatically detects and blocks email addresses in prompts before they reach Claude, providing a privacy safety net that works on every single prompt submission.

Prerequisites

  • Claude Code installed and working
  • UV installed (Python package manager)
  • Basic understanding of JSON configuration
  • A terminal/command prompt open

Steps

Step 1: Create Project Directory Structure

Create the project directory and subdirectories:

mkdir blocking-emails-in-prompts
cd blocking-emails-in-prompts
mkdir -p .claude/hooks
mkdir -p logs

Verify the structure:

ls -la

Step 2: Configure the Hook

Create .claude/settings.json with the UserPromptSubmit hook configuration:

cat > .claude/settings.json << 'EOF'
{
  "hooks": {
    "UserPromptSubmit": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "uv run .claude/hooks/prompt_email_blocker.py"
          }
        ]
      }
    ]
  }
}
EOF

Step 3: Create the Email Detection Hook

Create .claude/hooks/prompt_email_blocker.py with the email blocking logic:

cat > .claude/hooks/prompt_email_blocker.py << 'EOF'
#!/usr/bin/env python3
"""
# /// script
# requires-python = ">=3.8"
# dependencies = []
# ///

Claude Code UserPromptSubmit Hook: Email Address Detection and Blocking

This hook runs before Claude processes any user prompt and blocks prompts
that contain email addresses to prevent accidental PII exposure.

Privacy Guarantee: Prompts with emails never reach Claude.
"""

import json
import sys
import re
from datetime import datetime
from pathlib import Path


def detect_emails(content):
    """
    Detect email addresses in text content.
    
    Returns:
        dict: {
            'has_emails': bool,
            'count': int,
            'redacted_emails': list of redacted email examples
        }
    """
    # Email regex pattern
    email_pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
    
    # Find all email matches
    emails = re.findall(email_pattern, content, re.IGNORECASE)
    
    # Redact emails for safe logging (show only domain)
    redacted_emails = []
    for email in emails[:3]:  # Show max 3 examples
        if '@' in email:
            username, domain = email.split('@', 1)
            redacted = f"***@{domain}"
            redacted_emails.append(redacted)
    
    return {
        'has_emails': len(emails) > 0,
        'count': len(emails),
        'redacted_emails': redacted_emails
    }


def log_hook_execution(event_type, data):
    """Log hook execution to JSON file."""
    log_dir = Path("logs")
    log_dir.mkdir(exist_ok=True)
    
    log_entry = {
        "timestamp": datetime.now().isoformat(),
        "event_type": event_type,
        "data": data
    }
    
    log_file = log_dir / "prompt_blocker.json"
    
    # Append to existing log file
    logs = []
    if log_file.exists():
        try:
            with open(log_file, 'r') as f:
                logs = json.load(f)
        except:
            logs = []
    
    logs.append(log_entry)
    
    # Keep only last 50 entries
    logs = logs[-50:]
    
    with open(log_file, 'w') as f:
        json.dump(logs, f, indent=2)


def main():
    """Main hook execution logic."""
    try:
        # Read hook input from stdin
        hook_input = json.load(sys.stdin)
        
        # Extract the user's prompt
        prompt = hook_input.get("prompt", "")
        session_id = hook_input.get("session_id", "")
        
        if not prompt:
            log_hook_execution("no_prompt", {
                "session_id": session_id,
                "reason": "no prompt content found"
            })
            sys.exit(0)
        
        # Run email detection on the prompt
        email_result = detect_emails(prompt)
        
        if email_result['has_emails']:
            # Emails detected in prompt - block it
            error_message = f"""
🚫 EMAIL ADDRESSES DETECTED IN PROMPT - BLOCKED

Found {email_result['count']} email address(es) in your prompt:
Examples: {', '.join(email_result['redacted_emails'])}

Your prompt contains email addresses and has been blocked to protect privacy.

To proceed:
1. Remove or redact the email addresses from your prompt
2. Use placeholder emails like 'user@example.com' instead
3. Replace emails with descriptions like '[team email]' or '[customer email]'

Privacy Protection: Your prompt was not sent to Claude.

Original prompt length: {len(prompt)} characters
"""
            
            log_hook_execution("prompt_blocked", {
                "session_id": session_id,
                "email_count": email_result['count'],
                "redacted_emails": email_result['redacted_emails'],
                "prompt_length": len(prompt)
            })
            
            print(error_message.strip(), file=sys.stderr)
            sys.exit(2)  # Exit code 2 blocks the prompt from reaching Claude
        
        else:
            # No emails detected - allow prompt
            log_hook_execution("prompt_allowed", {
                "session_id": session_id,
                "prompt_length": len(prompt),
                "reason": "no emails detected"
            })
            
            # Optional: Show confirmation for transparency
            # print(f"āœ… Prompt cleared (no emails detected)", file=sys.stderr)
            sys.exit(0)
    
    except Exception as e:
        # Log unexpected errors
        log_hook_execution("hook_error", {
            "error": str(e),
            "error_type": type(e).__name__
        })
        
        # Don't block on hook errors - let Claude proceed
        print(f"Hook error (allowing prompt): {e}", file=sys.stderr)
        sys.exit(0)


if __name__ == "__main__":
    main()
EOF

Make the hook executable:

chmod +x .claude/hooks/prompt_email_blocker.py

Step 4: Test the Hook

Test with a safe prompt (should work normally):

claude "Help me write a Python function to calculate the factorial of a number"

Test with an email in the prompt (should be blocked):

claude "Please email the project update to john.doe@company.com and let me know when it's sent"

Step 5: Examine the Hook Logs

Check what the hook has recorded:

cat logs/prompt_blocker.json

Example Usage

Here's a complete example showing the hook in action:

# Navigate to your project
cd blocking-emails-in-prompts

# Test with a prompt containing multiple emails
claude "Send meeting invites to alice@company.com, bob@partner.org, and carol@client.net for tomorrow's review"

Expected Output

When an email is detected, you'll see:

🚫 EMAIL ADDRESSES DETECTED IN PROMPT - BLOCKED

Found 3 email address(es) in your prompt:
Examples: ***@company.com, ***@partner.org, ***@client.net

Your prompt contains email addresses and has been blocked to protect privacy.

To proceed:
1. Remove or redact the email addresses from your prompt
2. Use placeholder emails like 'user@example.com' instead
3. Replace emails with descriptions like '[team email]' or '[customer email]'

Privacy Protection: Your prompt was not sent to Claude.

Original prompt length: 91 characters

Tips & Variations

  • Whitelist specific domains: Modify the hook to allow certain domains like @example.com
  • Extend to other PII: Add detection for phone numbers, SSNs, or credit card numbers
  • Team deployment: Share the .claude/ directory with your team via version control
  • Custom messages: Tailor the error message to your organization's privacy policies

Troubleshooting

  • Issue: Hook not executing Solution: Ensure the hook file is executable (chmod +x) and UV is installed

  • Issue: Legitimate technical discussions about emails are blocked Solution: Use placeholders like "user@example.com" or "[email]" in your prompts

  • Issue: Logs directory not created Solution: The hook creates it automatically, but ensure you have write permissions

  • Issue: Hook allows emails through Solution: Check that .claude/settings.json is properly formatted and in the right location

Technical Deep Dive

šŸ“– Detailed Code Documentation

For a comprehensive breakdown of the code implementation, including:

  • Email detection logic and regex patterns
  • Logging system implementation
  • Error handling strategies
  • Alternative implementation approaches

View the detailed code documentation →

Real-World Applications

Enterprise Development

  • Prevent developers from including real customer emails in prompts
  • Block internal email addresses from being sent to external AI services
  • Protect employee contact information during troubleshooting

Compliance Requirements

  • GDPR compliance for EU email addresses
  • Corporate data protection policies
  • Audit trail for compliance reporting

Development Best Practices

  • Train developers to use placeholder emails
  • Prevent PII from entering AI training data
  • Secure prompt engineering practices

References

Master Claude Code with Expert Training

These recipes are from our comprehensive 2-day training course. Learn directly from experts and transform your development workflow.