DPDK patches and discussions
 help / color / mirror / Atom feed
From: Stephen Hemminger <stephen@networkplumber.org>
To: hau@realtek.com, drc@linux.ibm.com, howard_wang@realsil.com.cn,
	jianwang@trustnetic.com, jiawenwu@trustnetic.com,
	sachin.saxena@oss.nxp.com, xing_wang@realsil.com.cn,
	zaiyuwang@trustnetic.com
Cc: dev@dpdk.org
Subject: MAINTAINERS checkin
Date: Sat, 6 Sep 2025 09:19:32 -0700	[thread overview]
Message-ID: <20250906091932.33d61730@hermes.local> (raw)

[-- Attachment #1: Type: text/plain, Size: 758 bytes --]

The following email addresses no longer appear to be valid.
See attached python script (AI generated) for validation.

Invalid Emails:
------------------------------
• hau@realtek.com
  - Domain does not exist or is unreachable
• drc@linux.ibm.com
  - Domain does not exist or is unreachable
• howard_wang@realsil.com.cn
  - Domain does not exist or is unreachable
• jianwang@trustnetic.com
  - Domain does not exist or is unreachable
• jiawenwu@trustnetic.com
  - Domain does not exist or is unreachable
• sachin.saxena@oss.nxp.com
  - Domain does not exist or is unreachable
• xing_wang@realsil.com.cn
  - Domain does not exist or is unreachable
• zaiyuwang@trustnetic.com
  - Domain does not exist or is unreachable


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: email_validator.py --]
[-- Type: text/x-python, Size: 7712 bytes --]

#!/usr/bin/env python3
"""
Email Address Validator
Reads a list of email addresses from a file and validates them.
Performs both syntax validation and basic domain checking.
"""

import re
import sys
import socket
import argparse
from typing import List, Tuple, Dict
from pathlib import Path

class EmailValidator:
    def __init__(self):
        # RFC 5322 compliant email regex (simplified but robust)
        self.email_pattern = re.compile(
            r'^[a-zA-Z0-9.!#$%&\'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$'
        )
    
    def validate_syntax(self, email: str) -> bool:
        """Validate email syntax using regex."""
        if not email or len(email) > 254:
            return False
        
        # Split local and domain parts
        parts = email.rsplit('@', 1)
        if len(parts) != 2:
            return False
        
        local_part, domain = parts
        
        # Check local part length (max 64 characters)
        if len(local_part) > 64:
            return False
        
        # Use regex for full validation
        return bool(self.email_pattern.match(email))
    
    def validate_domain(self, email: str) -> bool:
        """Validate domain by checking if MX or A record exists."""
        try:
            domain = email.split('@')[1]
            
            # Try to get MX record first (preferred for email)
            try:
                socket.getaddrinfo(domain, None)
                return True
            except socket.gaierror:
                return False
                
        except (IndexError, socket.error):
            return False
    
    def validate_email(self, email: str, check_domain: bool = True) -> Dict[str, any]:
        """
        Comprehensive email validation.
        Returns a dict with validation results.
        """
        email = email.strip().lower()
        
        result = {
            'email': email,
            'valid_syntax': False,
            'valid_domain': False,
            'overall_valid': False,
            'errors': []
        }
        
        # Check syntax
        if self.validate_syntax(email):
            result['valid_syntax'] = True
        else:
            result['errors'].append('Invalid email syntax')
        
        # Check domain if syntax is valid
        if result['valid_syntax'] and check_domain:
            if self.validate_domain(email):
                result['valid_domain'] = True
            else:
                result['errors'].append('Domain does not exist or is unreachable')
        elif not check_domain:
            result['valid_domain'] = True  # Skip domain check
        
        # Overall validity
        result['overall_valid'] = result['valid_syntax'] and result['valid_domain']
        
        return result

def read_emails_from_file(file_path: str) -> List[str]:
    """Read email addresses from a file, one per line."""
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            emails = [line.strip() for line in f if line.strip()]
        return emails
    except FileNotFoundError:
        print(f"Error: File '{file_path}' not found.")
        sys.exit(1)
    except IOError as e:
        print(f"Error reading file '{file_path}': {e}")
        sys.exit(1)

def print_results(results: List[Dict], verbose: bool = False):
    """Print validation results in a formatted way."""
    valid_count = sum(1 for r in results if r['overall_valid'])
    total_count = len(results)
    
    print(f"\nValidation Results:")
    print(f"=" * 50)
    print(f"Total emails checked: {total_count}")
    print(f"Valid emails: {valid_count}")
    print(f"Invalid emails: {total_count - valid_count}")
    print(f"Success rate: {(valid_count/total_count)*100:.1f}%")
    print()
    
    if verbose:
        print("Detailed Results:")
        print("-" * 50)
        for result in results:
            status = "✓ VALID" if result['overall_valid'] else "✗ INVALID"
            print(f"{status:10} | {result['email']}")
            if result['errors']:
                for error in result['errors']:
                    print(f"           | Error: {error}")
        print()
    
    # Show invalid emails
    invalid_emails = [r for r in results if not r['overall_valid']]
    if invalid_emails:
        print("Invalid Emails:")
        print("-" * 30)
        for result in invalid_emails:
            print(f"• {result['email']}")
            for error in result['errors']:
                print(f"  - {error}")
        print()

def save_results(results: List[Dict], output_file: str):
    """Save results to a file."""
    try:
        with open(output_file, 'w', encoding='utf-8') as f:
            f.write("Email,Valid,Syntax_Valid,Domain_Valid,Errors\n")
            for result in results:
                errors_str = '; '.join(result['errors']) if result['errors'] else ''
                f.write(f"{result['email']},{result['overall_valid']},"
                       f"{result['valid_syntax']},{result['valid_domain']},\"{errors_str}\"\n")
        print(f"Results saved to: {output_file}")
    except IOError as e:
        print(f"Error saving results to '{output_file}': {e}")

def main():
    parser = argparse.ArgumentParser(
        description='Validate email addresses from a file',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  python email_validator.py emails.txt
  python email_validator.py emails.txt --no-domain-check
  python email_validator.py emails.txt --verbose --output results.csv
  python email_validator.py emails.txt -v -o validated_emails.csv
        """
    )
    
    parser.add_argument('input_file', help='Path to file containing email addresses (one per line)')
    parser.add_argument('--no-domain-check', action='store_true', 
                       help='Skip domain validation (faster, syntax-only)')
    parser.add_argument('-v', '--verbose', action='store_true',
                       help='Show detailed results for each email')
    parser.add_argument('-o', '--output', help='Save results to CSV file')
    
    args = parser.parse_args()
    
    # Check if input file exists
    if not Path(args.input_file).exists():
        print(f"Error: Input file '{args.input_file}' does not exist.")
        sys.exit(1)
    
    # Read emails from file
    print(f"Reading emails from: {args.input_file}")
    emails = read_emails_from_file(args.input_file)
    
    if not emails:
        print("No email addresses found in the file.")
        sys.exit(1)
    
    print(f"Found {len(emails)} email addresses to validate.")
    
    # Validate emails
    validator = EmailValidator()
    results = []
    
    check_domain = not args.no_domain_check
    if not check_domain:
        print("Note: Domain checking is disabled (syntax validation only)")
    
    print("\nValidating emails...")
    for i, email in enumerate(emails, 1):
        if args.verbose:
            print(f"Checking {i}/{len(emails)}: {email}", end="")
        
        result = validator.validate_email(email, check_domain)
        results.append(result)
        
        if args.verbose:
            status = " ✓" if result['overall_valid'] else " ✗"
            print(status)
    
    # Print results
    print_results(results, args.verbose)
    
    # Save results if requested
    if args.output:
        save_results(results, args.output)

if __name__ == "__main__":
    main()

                 reply	other threads:[~2025-09-06 16:19 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250906091932.33d61730@hermes.local \
    --to=stephen@networkplumber.org \
    --cc=dev@dpdk.org \
    --cc=drc@linux.ibm.com \
    --cc=hau@realtek.com \
    --cc=howard_wang@realsil.com.cn \
    --cc=jianwang@trustnetic.com \
    --cc=jiawenwu@trustnetic.com \
    --cc=sachin.saxena@oss.nxp.com \
    --cc=xing_wang@realsil.com.cn \
    --cc=zaiyuwang@trustnetic.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).