El parámetro strict de email.utils.getaddresses permite analizar listas de direcciones con reglas más rigurosas. Resulta especialmente útil cuando una aplicación procesa valores de To, Cc o Reply-To provenientes de mensajes externos, formularios, APIs o datos importados. En vez de aceptar estructuras malformadas y corregirlas de manera silenciosa, el modo estricto facilita detectar y rechazar entradas ambiguas.
Qué hace getaddresses
getaddresses recibe una secuencia de cadenas y devuelve pares con nombre visible y dirección. Interpreta comas, nombres entre comillas, corchetes angulares y la sintaxis habitual de buzones.
from email.utils import getaddresses
cabeceras = [
'Ana <ana@example.com>, Bruno <bruno@example.com>'
]
for nombre, direccion in getaddresses(cabeceras, strict=True):
print(nombre, direccion)
Con strict=True, una entrada inválida tiene menos posibilidades de convertirse en un resultado que solo parece correcto. Esto define una frontera más clara entre datos aceptados y rechazados.
Por qué importa el modo estricto
Un parser permisivo puede ocultar problemas. Una lista mal escrita puede interpretarse de manera distinta a la intención del usuario, provocar envíos equivocados, crear registros inconsistentes o facilitar evasiones de filtros. El modo estricto reduce esa ambigüedad.
Aun así, el parsing estricto es solo una capa. No demuestra que el dominio exista, que el buzón reciba mensajes ni que la dirección pertenezca a una persona concreta. Conviene combinarlo con reglas de dominio, confirmación por correo, límites y autorización propia de la aplicación.
Validar los valores obtenidos
No asumas que todos los pares devueltos son utilizables. Comprueba cadenas vacías y aplica reglas adicionales:
from email.utils import getaddresses
def extraer_destinatarios(valores: list[str]) -> list[str]:
destinatarios = []
for nombre, direccion in getaddresses(valores, strict=True):
direccion = direccion.strip()
if not direccion or '@' not in direccion:
raise ValueError('Dirección inválida')
destinatarios.append(direccion)
if not destinatarios:
raise ValueError('No hay destinatarios válidos')
return destinatarios
En producción también puedes limitar la cantidad de destinatarios, rechazar caracteres de control y aplicar una lista permitida de dominios.
Evitar una normalización destructiva
Muchas aplicaciones convierten toda la dirección a minúsculas. Puede ser práctico para comparar, pero la parte local es técnicamente sensible a mayúsculas en algunos sistemas. Conserva el valor original y crea una clave normalizada aparte cuando sea necesario.
No elimines signos de suma, puntos, guiones o guiones bajos sin una razón específica del proveedor. Una limpieza agresiva puede transformar una dirección válida en otra distinta. Puedes ampliar conceptos en la sección de Python y en los artículos de Python avanzado.
Separar parsing y autorización
El parsing responde si la estructura parece una lista válida. La autorización decide si la dirección puede utilizarse en ese contexto. Mantén ambas responsabilidades separadas.
DOMINIOS_PERMITIDOS = {'example.com', 'empresa.com'}
def esta_permitido(direccion: str) -> bool:
_, dominio = direccion.rsplit('@', 1)
return dominio.lower() in DOMINIOS_PERMITIDOS
Este diseño facilita las pruebas y evita mezclar reglas de negocio con el análisis sintáctico.
Entradas procedentes de la web
Cuando las direcciones llegan desde un navegador o API pública, aplica límites antes del parsing. Restringe la longitud total del campo y el número máximo de destinatarios. Una entrada enorme puede consumir CPU, memoria y espacio de logs.
Rechaza retornos de carro y saltos de línea suministrados por usuarios. Los caracteres \r y \n pueden causar inyección de cabeceras. Es preferible usar las clases estructuradas del paquete email en lugar de concatenar cadenas manualmente.
Usar un modelo de datos
from dataclasses import dataclass
from email.utils import getaddresses
@dataclass(frozen=True)
class Destinatario:
nombre: str
direccion: str
def analizar_destinatarios(valores: list[str]) -> list[Destinatario]:
elementos = []
for nombre, direccion in getaddresses(valores, strict=True):
if not direccion or '@' not in direccion:
raise ValueError(f'Entrada inválida: {nombre!r}')
elementos.append(Destinatario(nombre.strip(), direccion.strip()))
return elementos
Un modelo inmutable evita cambios accidentales después de la validación y funciona bien en APIs, colas y servicios de envío.
Pruebas importantes
Prueba direcciones simples, nombres entre comillas, múltiples destinatarios, valores vacíos, comas adicionales, corchetes mal formados, duplicados, nombres Unicode y límites máximos.
def test_destinatario_valido():
elementos = analizar_destinatarios(['Ana <ana@example.com>'])
assert elementos[0].direccion == 'ana@example.com'
def test_destinatario_invalido():
try:
analizar_destinatarios(['no es una direccion'])
except ValueError:
pass
else:
raise AssertionError('Se esperaba ValueError')
Consulta también los contenidos de pruebas y las guías de automatización.
Compatibilidad entre versiones
Confirma la versión mínima de Python admitida antes de usar strict. Si una biblioteca debe funcionar en intérpretes antiguos, aísla la compatibilidad en una función documentada y pruébala en integración continua.
No captures cualquier TypeError para repetir automáticamente sin modo estricto. Ese patrón puede ocultar errores de programación que no tienen relación con la versión. Es mejor usar comprobaciones explícitas o un adaptador bien probado.
Límites de seguridad
El parsing estricto no vuelve confiable una dirección. No uses el texto analizado como comando, ruta, fragmento SQL ni token de autorización. Cada destino necesita su propia validación.
Los logs también requieren cuidado. Registrar listas completas puede exponer datos personales. Cuando no sea imprescindible, guarda un identificador de solicitud, la cantidad de direcciones, un resumen de dominios o valores parcialmente ocultos.
Eliminar duplicados
Es común eliminar duplicados conservando el orden:
def destinatarios_unicos(direcciones: list[str]) -> list[str]:
vistos = set()
resultado = []
for direccion in direcciones:
clave = direccion.casefold()
if clave not in vistos:
vistos.add(clave)
resultado.append(direccion)
return resultado
Decide si la deduplicación se aplica entre To, Cc y Bcc. Conserva las categorías originales cuando la privacidad o la auditoría dependan de ellas.
Mensajes de error
Los mensajes públicos deben ser útiles sin revelar detalles internos del parser. “Una o más direcciones no son válidas” suele ser más seguro que repetir la entrada completa. Los logs internos pueden guardar diagnósticos estructurados con los datos sensibles ocultos.
Referencias oficiales
La documentación de email.utils explica las funciones auxiliares y el comportamiento por versión. El formato completo de mensajes de Internet está definido en la RFC 5322.
Conclusión
email.utils.getaddresses(..., strict=True) ofrece un punto de partida más sólido para analizar destinatarios. Úsalo junto con comprobaciones explícitas, límites de tamaño, modelos inmutables, reglas de seguridad y pruebas completas. El modo estricto reduce la ambigüedad, mientras que la arquitectura que lo rodea determina la fiabilidad final del sistema.







