---
name: clean_email
kind: function
lang: py
domain: core
version: "1.0.0"
purity: pure
signature: "def clean_email(raw: str) -> str"
description: "Normaliza un email crudo que puede provenir de fuentes sucias (TSVs, CSVs, hojas de calculo). Elimina whitespace, angle brackets y comillas, convierte a minusculas y valida la forma basica. Lanza ValueError si el resultado no es un email plausible."
tags: [email, sanitize, validation, core]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: []
tested: true
tests:
  - "angle brackets y whitespace se limpian"
  - "comillas dobles y mayusculas se normalizan"
  - "whitespace puro se limpia y lowercase"
  - "email sin arroba lanza ValueError"
  - "string vacio lanza ValueError"
  - "email sin punto en dominio lanza ValueError"
test_file_path: "python/functions/core/clean_email_test.py"
file_path: "python/functions/core/clean_email.py"
params:
  - name: raw
    desc: "String crudo con la direccion de email, potencialmente rodeado de whitespace, angle brackets (<foo@bar.com>) o comillas simples/dobles."
output: "Email limpio en minusculas con la forma 'local@dominio.tld'. Lanza ValueError si no es un email plausible tras la limpieza."
---

## Ejemplo

```python
from core.clean_email import clean_email

# Caso tipico de TSV/Outlook con angle brackets y whitespace
clean_email(" <eaznarez@mutuamadmotor.com>")
# -> "eaznarez@mutuamadmotor.com"

# Comillas dobles y mayusculas desde spreadsheet
clean_email('"BAR@BAZ.com"')
# -> "bar@baz.com"

# Caso invalido: lanza ValueError
import pytest
with pytest.raises(ValueError):
    clean_email("not-an-email")
```

## Cuando usarla

Antes de enviar una direccion de email a una API que valida estrictamente (ej. Metabase `POST /api/user`, SendGrid, etc.) cuando el origen del dato es un CSV, TSV, Excel, o campo pegado a mano. Usar esta funcion como paso de limpieza antes de cualquier llamada de creacion de usuarios o envio de correos.

## Gotchas

- NO valida registros MX ni que el dominio exista realmente — solo comprueba forma basica (un `@`, local part no vacia, al menos un `.` en el dominio).
- NO decodifica quoted-printable ni dominios IDN/internacionales — solo limpieza de caracteres ASCII de envoltura.
