(+351) 21 24 10006  ·  info@bconcepts.pt
Carnaxide, Lisboa

Cómo validar y limpiar correos electrónicos en Python para datos: paso a paso

João Barros 22 de August de 2026 4 min de lectura

Aprender a validar y limpiar correos electrónicos en Python para datos es útil para mejorar la calidad de las bases de datos, reducir fallos en el envío de notificaciones y garantizar una mejor correspondencia entre registros. Este tutorial muestra cómo detectar formatos inválidos, normalizar dominios comunes y eliminar duplicados de forma práctica.

Requisitos previos

  • Python 3.8+ instalado.
  • Bibliotecas: pandas, email-validator (instalación vía pip).
  • Editor de texto o Jupyter Notebook.

Paso 1: Instalar dependencias

Instala las bibliotecas necesarias. La biblioteca email-validator realiza la validación sintáctica y algunas correcciones básicas; pandas facilita la manipulación de datos.

pip install pandas email-validator

Paso 2: Cargar datos de ejemplo

Crea un DataFrame simple con correos que contengan errores comunes: espacios, mayúsculas, puntos duplicados, dominios con typos y entradas vacías.

import pandas as pd

df = pd.DataFrame({
    'id': [1,2,3,4,5,6],
    'email': [
        'Joao.Silva@Exemplo.COM ',
        'maria..souza@@gmail.com',
        'ana@gnail.con',
        '  ',
        'pedro@exemplo.com',
        'PEDRO@Exemplo.com'
    ]
})
print(df)

Paso 3: Normalizar cadenas básicas

Elimina espacios en blanco alrededor, convierte a minúsculas y reduce puntos duplicados en la parte local del correo. Esto reduce diferencias triviales entre direcciones.

def normalize_basic(email):
    if not isinstance(email, str):
        return ''
    e = email.strip().lower()
    # reducir puntos duplicados en la parte antes de @
    if '@' in e:
        local, domain = e.split('@', 1)
        while '..' in local:
            local = local.replace('..', '.')
        e = f"{local}@{domain}"
    return e

df['email_norm'] = df['email'].apply(normalize_basic)
print(df[['email','email_norm']])

Paso 4: Validar sintaxis con email-validator

Usa email-validator para verificar si el formato es válido y recibir recomendaciones. La función a continuación devuelve un estado y la versión normalizada por el validador cuando es posible.

from email_validator import validate_email, EmailNotValidError

def validate_email_safe(email):
    if not email:
        return {'valid': False, 'reason': 'empty', 'email': ''}
    try:
        v = validate_email(email, check_deliverability=False)
        return {'valid': True, 'reason': '', 'email': v.email}
    except EmailNotValidError as e:
        return {'valid': False, 'reason': str(e), 'email': ''}

res = df['email_norm'].apply(validate_email_safe)
res_df = pd.json_normalize(res)
df = pd.concat([df, res_df.add_prefix('val_')], axis=1)
print(df[['email_norm','val_valid','val_reason','val_email']])

Paso 5: Corregir dominios comunes con typos

Muchos errores provienen de dominios escritos incorrectamente (p. ej.: gnail -> gmail). Crea un diccionario de correcciones para aplicar después de la validación sintáctica.

COMMON_DOMAINS = {
    'gnail.com': 'gmail.com',
    'gnail.con': 'gmail.com',
    'exemplo.com': 'exemplo.com',  # ejemplo deseado
}

def fix_common_domain(email):
    if not email or '@' not in email:
        return email
    local, domain = email.split('@', 1)
    domain_fix = COMMON_DOMAINS.get(domain, domain)
    return f"{local}@{domain_fix}"

# aplicar solo donde hay un email validado en val_email o intentar usar email_norm
df['email_fixed'] = df['val_email'].where(df['val_email'] != '', df['email_norm']).apply(fix_common_domain)
print(df[['email_norm','val_email','email_fixed']])

Paso 6: Revalidar y marcar inválidos

Revalida los correos corregidos para separar los que siguen inválidos. Mantén una columna con el estado final: valid/invalid/unknown.

final_res = df['email_fixed'].apply(validate_email_safe)
final_df = pd.json_normalize(final_res)
df = pd.concat([df, final_df.add_prefix('final_')], axis=1)

def status(row):
    if row['final_valid']:
        return 'valid'
    if not row['email_fixed']:
        return 'invalid'
    return 'invalid'

df['status'] = df.apply(status, axis=1)
print(df[['email','email_fixed','final_valid','status']])

Paso 7: Eliminar duplicados y consolidar

Al normalizar y corregir, es frecuente que aparezcan duplicados (p. ej.: pedro@exemplo.com y PEDRO@Exemplo.com). Usa pandas para desduplicar manteniendo el primer registro o agregando IDs.

# crear clave para desduplicar
clean = df[df['status']=='valid'].copy()
clean['email_canonical'] = clean['email_fixed']
# mantener el primer id por email
clean_dedup = clean.drop_duplicates(subset=['email_canonical'], keep='first')
print(clean_dedup[['id','email','email_canonical']])

Verificar el resultado

Confirma que los correos válidos están normalizados, los inválidos identificados y los duplicados eliminados. Verifica números: total original, válidos finales, inválidos y duplicados eliminados.

total = len(df)
validos = df['status'].eq('valid').sum()
invalidos = df['status'].eq('invalid').sum()
deduped = len(clean_dedup)
print(f"Total: {total}, Válidos: {validos}, Inválidos: {invalidos}, Después de deduplicación: {deduped}")

Conclusión

Ahora tienes un proceso sencillo para normalizar, validar y limpiar correos electrónicos en Python para datos, incluyendo correcciones de dominios y deduplicación. Próximos pasos: integrar este pipeline en un ETL, usar check_deliverability=True con precaución o enriquecer con validación SMTP. Consejo: mantén un registro de las correcciones para auditar los cambios en los correos.