DEV Community

Cover image for How to build a Python email-checker using the Mail7 API (and spot disposable addresses like TempMailbox)
Den
Den

Posted on

How to build a Python email-checker using the Mail7 API (and spot disposable addresses like TempMailbox)

Want to verify whether an email is real (deliverable) or just a throwaway disposable address (e.g. TempMailbox)? In this post I’ll show the purpose, how to write a small Python script that uses the Mail7 public Email Checker API, and how to use it in simple workflows (single-check, bulk-check, rate-limit handling). Code examples are ready-to-run and easy to adapt for production use.

Why this is useful

  • Prevent fake or disposable emails polluting your database (improves deliverability & analytics).
  • Reduce fraud, reduce bounce rates and protect downstream workflows (password resets, marketing).
  • Lightweight: Mail7’s API is public and simple — you don’t need API keys to get started. 

(Example disposable service referenced in this post: TempMailbox — a typical disposable/temp-mail provider.)

Quick notes from Mail7 docs (what matters)

  • Base URL: https://mail7.net. No authentication required — it’s a public API. 
  • Rate limit: 5 requests / minute / IP. Exceeding it returns HTTP 429 with a Retry-After header. Your script should respect this. 
  • Key endpoints used here:
  1. POST /api/validate-single — single email check (JSON body {"email": "..."} ). Response contains valid, formatValid, mxValid, smtpValid, status, details and importantly is_disposable. 
  2. POST /api/validate-bulk — upload file or text list for bulk checks. Useful for offline cleanup. 
  3. GET /api/spf-check/{domain} - optional: check domain SPF if you want to add additional heuristics.

The Python script (complete, annotated)

Save as mail7_check.py. It does:

  • single-check via /api/validate-single
  • handles rate-limit (429 + Retry-After)
  • simple backoff on server errors
  • can be used interactively or imported as a module
#!/usr/bin/env python3
"""
mail7_check.py
Simple utilities to check an email address using Mail7 Email Checker API.
"""

import time
import requests
from typing import Dict, Optional

BASE = "https://mail7.net"
SINGLE_ENDPOINT = f"{BASE}/api/validate-single"
BULK_ENDPOINT = f"{BASE}/api/validate-bulk"
SPF_ENDPOINT = f"{BASE}/api/spf-check/{{}}"

# Simple wrapper for single validation
def validate_single(email: str, timeout: float = 10.0) -> Dict:
    """Validate a single email. Returns the parsed JSON response."""
    payload = {"email": email}
    headers = {"Content-Type": "application/json"}
    while True:
        resp = requests.post(SINGLE_ENDPOINT, json=payload, headers=headers, timeout=timeout)
        if resp.status_code == 200:
            return resp.json()
        if resp.status_code == 429:
            # Respect Retry-After header if present
            retry = resp.headers.get("Retry-After")
            wait = int(retry) if retry and retry.isdigit() else 60
            print(f"[rate-limit] 429 received. Waiting {wait} seconds...")
            time.sleep(wait)
            continue
        if 500 <= resp.status_code < 600:
            # transient server error, back off a bit
            print(f"[server-error] {resp.status_code}. Backing off 5s...")
            time.sleep(5)
            continue
        # For other errors, raise
        resp.raise_for_status()

def is_good_email(result: Dict) -> bool:
    """
    Heuristic to decide whether to accept this email:
      - result['valid'] should be True
      - smtpValid and mxValid are helpful
      - is_disposable should be False
      - status normally contains 'Valid' for good addresses
    Adapt this logic to your business needs.
    """
    if not result:
        return False
    if result.get("is_disposable"):
        return False
    # require overall valid + smtp existence
    if result.get("valid") and result.get("smtpValid"):
        return True
    # fallback: format + mx
    if result.get("formatValid") and result.get("mxValid"):
        return True
    return False

def pretty_print(result: Dict):
    print("email:", result.get("email"))
    print("status:", result.get("status"))
    print("valid:", result.get("valid"))
    print("formatValid:", result.get("formatValid"))
    print("mxValid:", result.get("mxValid"))
    print("smtpValid:", result.get("smtpValid"))
    print("is_disposable:", result.get("is_disposable"))
    print("details:", result.get("details"))

if __name__ == "__main__":
    import argparse
    parser = argparse.ArgumentParser(description="Check email validity using mail7.net API")
    parser.add_argument("email", help="Email to check, or path to file with emails (one per line) if --bulk")
    parser.add_argument("--bulk", action="store_true", help="Treat argument as a file and run bulk check (calls validate-bulk)")
    args = parser.parse_args()

    if args.bulk:
        # Bulk mode: upload file to /api/validate-bulk (form data: 'emails')
        with open(args.email, "rb") as f:
            files = {"emails": (args.email, f)}
            r = requests.post(BULK_ENDPOINT, files=files)
            r.raise_for_status()
            data = r.json()
            print("Total:", data.get("total"))
            for item in data.get("results", []):
                print("----")
                pretty_print(item)
    else:
        res = validate_single(args.email)
        pretty_print(res)
        print("DECISION:", "ACCEPT" if is_good_email(res) else "REJECT")
Enter fullscreen mode Exit fullscreen mode

Requirements

pip install requests
python3 mail7_check.py [email to check]
# or bulk:
python3 mail7_check.py emails.txt --bulk
Enter fullscreen mode Exit fullscreen mode

How the script decides disposable vs real

Mail7’s response contains an is_disposable boolean. Use that directly to detect throwaway providers (like TempMailbox). Combine that with smtpValid and mxValid to be confident — smtpValid=true strongly indicates the address exists and accepts mail. 

Example logic in the script (is_good_email) returns False when is_disposable is true, or when the address fails SMTP checks.

Real-world usage examples

  • Signup form — call validate-single on email submission. If is_disposable is true or smtpValid is false, show a friendly error or ask the user for a non-disposable email.
  • CRM cleanup — every week, run a bulk pass with validate-bulk and remove invalid/disposable addresses from mailing lists.
  • Fraud screening — combine is_disposable with geo/IP/device signals for higher-risk signups.

Caveats & tips

  • False negatives/positives: No validation is perfect. Some providers block SMTP probes, some disposable providers forward to real addresses — combine signals (mx, smtp, is_disposable, and business rules).
  • Respect privacy & terms: Don’t leak results or perform abusive queries. If you need bulk/enterprise usage, contact Mail7 for a supported arrangement (the docs describe basic public API behavior).
  • Disposable services evolve. Lists of disposable domains change — relying solely on a static list is brittle. Using Mail7’s is_disposable is easier because they update their detection on the provider side.

Final notes & links

  • Mail7 API docs (use them as the definitive reference for endpoints, payloads and rate limits): https://mail7.net/api-docs.html. 
  • Example disposable provider for reference: https://tempmailbox.net (TempMailbox) — great example of a disposable mailbox you may want to block on registration. 

Top comments (0)