Tutorials

How to Validate Email Addresses in Python Using the MailRook API

Leo Zhavoronkov · · 4 min read
How to Validate Email Addresses in Python Using the MailRook API

How to Validate Email Addresses in Python Using the MailRook API

Validating email addresses before sending is essential for maintaining your sender reputation and reducing bounce rates. In this tutorial, you'll learn how to integrate the MailRook email validation API into your Python application.

Prerequisites

  • Python 3.8+
  • A MailRook account (free tier gives you 100 checks/day)
  • Your API key from the MailRook dashboard

Install Dependencies

You only need the requests library:

pip install requests

Single Email Validation

The simplest use case — validate one email address:

import requests

API_KEY = "your_api_key_here"
BASE_URL = "https://api.mailrook.com/v1"

def validate_email(email: str) -> dict:
    """Validate a single email address."""
    response = requests.get(
        f"{BASE_URL}/validate/{email}",
        headers={"Authorization": f"Bearer {API_KEY}"}
    )
    response.raise_for_status()
    return response.json()

# Usage
result = validate_email("[email protected]")
print(f"Email: {result['email']}")
print(f"Valid: {result['is_valid']}")
print(f"Reason: {result['reason']}")

Understanding the Response

The API returns a detailed validation result:

{
  "email": "[email protected]",
  "is_valid": false,
  "reason": "mailbox_not_found",
  "checks": {
    "syntax": true,
    "domain": true,
    "mx_records": true,
    "smtp": false,
    "disposable": false,
    "catch_all": false,
    "role_based": false
  },
  "response_time_ms": 342
}

Key fields:

  • is_valid — Whether the email can receive mail
  • reason — Why it failed (if invalid)
  • checks — Individual check results

Batch Validation

For validating entire lists, use the batch endpoint:

import requests
import time

def validate_batch(emails: list[str]) -> dict:
    """Submit a batch of emails for validation."""
    # Submit the batch
    response = requests.post(
        f"{BASE_URL}/validate/batch",
        headers={"Authorization": f"Bearer {API_KEY}"},
        json={"emails": emails}
    )
    response.raise_for_status()
    batch = response.json()
    list_uuid = batch["list_uuid"]
    
    # Poll for results
    while True:
        status = requests.get(
            f"{BASE_URL}/validate/list/{list_uuid}",
            headers={"Authorization": f"Bearer {API_KEY}"}
        ).json()
        
        if status["status"] == "completed":
            return status
        
        print(f"Progress: {status.get('progress', 0)}%")
        time.sleep(2)

# Usage
emails = [
    "[email protected]",
    "[email protected]",
    "[email protected]",
]

results = validate_batch(emails)
for result in results["results"]:
    status = "valid" if result["is_valid"] else "invalid"
    print(f"{result['email']}: {status}")

Validating at Signup (Django Example)

Add real-time validation to your Django registration form:

# validators.py
import requests
from django.core.exceptions import ValidationError

def validate_email_mailrook(email: str):
    """Django validator that checks email via MailRook."""
    try:
        response = requests.get(
            f"https://api.mailrook.com/v1/validate/{email}",
            headers={"Authorization": f"Bearer {API_KEY}"},
            timeout=5
        )
        result = response.json()
        
        if not result.get("is_valid"):
            reason = result.get("reason", "unknown")
            raise ValidationError(
                f"This email address appears to be invalid: {reason}"
            )
    except requests.RequestException:
        # Don't block signups if the API is unreachable
        pass
# models.py
from django.db import models
from .validators import validate_email_mailrook

class User(models.Model):
    email = models.EmailField(
        validators=[validate_email_mailrook]
    )

Validating a CSV File

Process an entire CSV of emails:

import csv
import requests

def validate_csv(input_path: str, output_path: str):
    """Read emails from CSV, validate, and write results."""
    with open(input_path) as infile:
        emails = [row[0].strip() for row in csv.reader(infile) if row]
    
    # Submit batch
    response = requests.post(
        f"{BASE_URL}/validate/batch",
        headers={"Authorization": f"Bearer {API_KEY}"},
        json={"emails": emails}
    )
    batch = response.json()
    
    # Wait for completion (simplified)
    import time
    while True:
        status = requests.get(
            f"{BASE_URL}/validate/list/{batch['list_uuid']}",
            headers={"Authorization": f"Bearer {API_KEY}"}
        ).json()
        if status["status"] == "completed":
            break
        time.sleep(2)
    
    # Write results
    with open(output_path, "w", newline="") as outfile:
        writer = csv.writer(outfile)
        writer.writerow(["email", "valid", "reason"])
        for result in status["results"]:
            writer.writerow([
                result["email"],
                result["is_valid"],
                result.get("reason", "")
            ])
    
    valid = sum(1 for r in status["results"] if r["is_valid"])
    total = len(status["results"])
    print(f"Validated {total} emails: {valid} valid, {total - valid} invalid")

# Usage
validate_csv("contacts.csv", "validated_contacts.csv")

Error Handling Best Practices

Always handle API errors gracefully:

import requests
from requests.exceptions import RequestException

def safe_validate(email: str) -> dict | None:
    """Validate with proper error handling."""
    try:
        response = requests.get(
            f"{BASE_URL}/validate/{email}",
            headers={"Authorization": f"Bearer {API_KEY}"},
            timeout=10
        )
        
        if response.status_code == 429:
            print("Rate limited — wait before retrying")
            return None
        
        if response.status_code == 401:
            print("Invalid API key")
            return None
            
        response.raise_for_status()
        return response.json()
        
    except RequestException as e:
        print(f"API request failed: {e}")
        return None

Next Steps

Ready to validate your email lists?

Start with 100 free email checks per day. No credit card required.

Get Started Free