Cómo validar y limpiar correos electrónicos en Python para datos: paso a paso
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.