Build a Email Validator in Python

Chetan TekamChetan Tekam
6 min read

Objective: Building a Email Validator in Python where script can processing a list of user inputs to generate a report of valid email addresses and their domains.

It demonstrates:

  • variables,

  • control structures (nested loops and conditionals),

  • functions,

  • exception handling,

  • functions (including *args and **kwargs)

  • basic string manipulation

  • pytest (for testing script)


What new Concept covered

*args (Variable Positional Arguments):

  • What: Allows a function to accept any number of positional arguments (e.g., generate_report(emails, "personal", "work")).

  • Why: Flexible for functions that need varying inputs (e.g., categories).

  • Where: Used in scripts or APIs to handle dynamic inputs.

  • New: *categories collects extra arguments as a tuple.

  • Exceptions: Misusing *args with incorrect types (handled by checking category.lower()).


**kwargs (Variable Keyword Arguments):

  • What: Allows a function to accept any number of keyword arguments similar like key-value pair (e.g., show_invalid=True).

  • Why: Provides optional configuration without fixed parameters.

  • Where: Common in utilities or APIs for customizable behavior.

  • New: **options collects keyword arguments as a dictionary; accessed with .get().

  • Exceptions: Missing keys (handled with .get(default)).


String Manipulation:

  • What: Uses split('@'), in operator, and lower() for email validation and domain extraction.

  • Why: Processes text data efficiently.

  • Where: Parsing user inputs or logs.

  • New: Basic email validation checks for @and a domain.

  • Exceptions: Invalid emails cause IndexError (handled in is_valid_email).


Nested Loops and any():

  • What: Nested loop in list comprehension (any(category.lower() in email.lower() ...)).

  • Why: Checks if any category matches an email, simplifying control flow.

  • Where: Filtering data based on multiple criteria.

  • New: any() is a Python built-in that returns True if any element in an iterable is True.

  • Exceptions: Empty iterables or case mismatches (handled with lower()).


Pytest:

  • What: A testing framework for Python to write and run tests.

  • Why: Automates verification of code functionality, ensuring reliability.

  • Where: Used in development to validate logic and in CI/CD pipelines for DevOps.

  • New: Tests are written as functions with assert statements; pytest discovers and runs them.

  • Exceptions: Test failures indicate bugs or incomplete test coverage.


Test Functions:

  • What: Functions like test_is_valid_email() that check specific behaviors.

  • Why: Isolates functionality for targeted validation.

  • Where: Unit testing individual components (e.g., email validation).

  • New: Prefix with test_ for pytest to recognize; use descriptive assertions.

  • Exceptions: Overly specific tests may break with minor code changes.


Importing Modules:

  • What: Importing functions from email_validator.py (e.g., from basics.email_validator import ...).

  • Why: Tests need access to the code being tested.

  • Where: Common in modular projects with separate test files.

  • New: Path-based import requires correct directory structure.

  • Exceptions: Incorrect paths cause ModuleNotFoundError.


Project summary

  1. Processing a list of user inputs to generate a report of valid email addresses and their domains.

  2. Understand difference and use of *args and **kwargs in functions.

  3. Why pytest needed - Automates verification of code functionality, ensuring reliability. .

  4. Importing Modules - Tests need access to the code being tested


Structure

core-python
β”œβ”€β”€ basics
β”‚   └── email_validator
β”‚       β”œβ”€β”€ README.md
β”‚       └── main.py
└── tests
    └── test_email_validator.py

How I Built it

  1. Build a pseudo flow chart with pen and paper.

  2. Start writing code:

    • Let’s start with main():

      • Execute each step with considering pseudo flow chart.

      • emails assign to a list of emails.

      • report1 assign to generate_report(emails) which return only valid emails.

      • report2 assign to generate_report(emails, "personal") which return only emails which has personal in it.

      • report3 assign to generate_report(emails, show_invalid=True) which return all emails (including invalid).

      • print_report() do the printing work.

  • About generate_report():

    • Generate report depending on passed arguments.

    • Take three arguments:

      • emails take all provided emails

      • *categories take all remaining argument after emails.

      • **options take only key-pair type argument. (e.g. show_invalid=True)

    • Return:

      • β†’ dict[str, list[str]] means a dictionary which has domain name and it’s corresponding email in a list.

  • About is_valid_email():

    • Check weather email is valid or not.

    • Has email parameter which takes email.

    • Return: β†’ bool means return be True or False.

  • About extract_domain():

    • Extract the domain from a valid email.

    • Has email parameter which takes email.

    • Return: β†’ str means return be

      • if email valid domain.com

      • if email is invalid ” β€œ.

  • About print_report():

    • First check report empty or not then do the printing work on report.

    • Has report parameter which take a report.

    • Return: β†’ None means no return.

How to run

  1. Change directoru to core-python, so that test can also be performed.

     # optional: in python-foundation dir
     # source venv/bin/activate    # Windows: venv\Scripts\activate
     cd core-python
    
  2. Run main.py.

     python3 basics/email_validator/main.py
    

    Output:

     Report 1: All valid emails
    
         Domain: gmail.com
           - alice@gmail.com
    
         Domain: work.com
           - bob@work.com
    
         Domain: yahoo.com
           - charlie.personal@yahoo.com
    
         Domain: outlook.com
           - dave@outlook.com
    
     Report 2: Personal emails only
    
         Domain: yahoo.com
           - charlie.personal@yahoo.com
    
     Report 3: All emails (including invalid)
    
         Domain: gmail.com
           - alice@gmail.com
    
         Domain: work.com
           - bob@work.com
    
         Domain: invalid
           - invalid.email
    
         Domain: yahoo.com
           - charlie.personal@yahoo.com
    
         Domain: outlook.com
           - dave@outlook.com
    
  3. Run test_email_validator.py:

     PYTHONPATH=. pytest tests/test_email_validator.py -vv
    

    Output:

     PYTHONPATH=. pytest tests/test_email_validator.py -vv
     ============================= test session starts ==============================
     platform linux -- Python 3.12.8, pytest-8.4.0, pluggy-1.6.0 -- /usr/bin/python3.12
     cachedir: .pytest_cache
     rootdir: /Path/to/repos/PYTHON-FOUNDATION/core-python
     plugins: anyio-4.9.0
     collected 4 items                                                              
    
     tests/test_email_validator.py::test_is_valid_email PASSED                [ 25%]
     tests/test_email_validator.py::test_extract_domain PASSED                [ 50%]
     tests/test_email_validator.py::test_generate_report PASSED               [ 75%]
     tests/test_email_validator.py::test_generate_report_edge_cases PASSED    [100%]
    
     ============================== 4 passed in 0.08s ===============================
    

Possible Issues

Of email_validator

  • Invalid Emails: Handled by is_valid_email() with IndexError` protection.

  • Empty Inputs: Empty email lists or categories (handled with checks).

  • Type Hints: Use mypy for static checking:

pip install mypy 
mypy basics/email_validator/main.py

Of Test

  • Test Failures: Indicate bugs in email_validator/main.py (e.g., incorrect domain extraction).

  • Module Import Errors: Ensure basics/email_validator/main.py exists; fix path if ModuleNotFoundError occurs.

  • Incomplete Coverage: Tests cover main cases but not every scenario (e.g., very long emails); add more as needed.

  • Pytest Setup: Ensure pytest is installed; update requirements.txt if missed.


Next

Functions demonstrates decorators and lambda functions.


Github: Repo - Python Foundation/email_validator

Click here for: Project list


🀝 How to Contribute / Follow Along

  • Clone the repo or copy scripts to try on your own machine.

  • Share your output or improvements in the comments.

  • DM me on GitHub or Hashnode for feedback!


πŸ“’ Let’s Connect

Follow me on Hashnode to get notified when I publish new Python projects πŸ‘‡

➑️ Chetan Tekam


0
Subscribe to my newsletter

Read articles from Chetan Tekam directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Chetan Tekam
Chetan Tekam