{"id":324,"date":"2026-11-02T21:20:14","date_gmt":"2026-11-02T20:20:14","guid":{"rendered":"https:\/\/n8nfacil.com\/?p=324"},"modified":"2026-11-02T21:20:14","modified_gmt":"2026-11-02T20:20:14","slug":"n8n-calidad-contactos-informe","status":"publish","type":"post","link":"https:\/\/n8nfacil.com\/en\/n8n-calidad-contactos-informe\/","title":{"rendered":"Control de calidad de contactos con n8n: v\u00e1lidos, duplicados y datos para revisar"},"content":{"rendered":"<p><strong>Pr\u00e1ctica local con datos ficticios.<\/strong> Pruebas de n8n 2.44.5 realizadas el 2 de noviembre de 2026. No requiere credenciales externas.<\/p><p>Una lista puede tener seis filas y solo dos contactos preparados para el siguiente paso. Borrar duplicados sin comprobar los datos puede esconder errores: un correo vac\u00edo se parece a otro correo vac\u00edo, y dos direcciones con espacios pueden parecer distintas aunque representen el mismo valor. Este proyecto aborda el lote completo y entrega tres listas separadas para decidir qu\u00e9 hacer despu\u00e9s.<\/p><h2>Qu\u00e9 resuelve y qu\u00e9 significa \u201cv\u00e1lido\u201d en esta pr\u00e1ctica<\/h2><p>El informe normaliza nombre y correo, comprueba que el nombre no est\u00e9 vac\u00edo y aplica una comprobaci\u00f3n sencilla del formato del email. Despu\u00e9s separa duplicados por correo normalizado. <strong>\u201cV\u00e1lido\u201d significa que supera estas reglas locales; no significa que el buz\u00f3n exista, que la direcci\u00f3n pertenezca a esa persona ni que tengas permiso para enviarle mensajes.<\/strong><\/p><p>La decisi\u00f3n de comparar el email en min\u00fasculas es una pol\u00edtica del ejercicio. Antes de aplicarla a una base real, define c\u00f3mo identifica contactos tu sistema. Tampoco se intenta deducir qu\u00e9 persona hay detr\u00e1s de dos correos distintos.<\/p><h2>1. Prepara los cuatro nodos<\/h2><p>Nivel intermedio. Necesitas n8n funcionando y conocimientos b\u00e1sicos de elementos, JSON y expresiones. La pr\u00e1ctica se ejecuta manualmente, con datos ficticios y sin conectar cuentas externas. No escribe en un CRM, no manda correos y no modifica un inventario real.<\/p><p>Crea un workflow vac\u00edo. A\u00f1ade Manual Trigger y tres nodos Code conectados en este orden: <strong>Ejecutar prueba \u2192 Datos de ejemplo \u2192 Evaluar registros \u2192 Informe del lote<\/strong>. En los tres nodos Code selecciona JavaScript y <strong>Run Once for All Items<\/strong>. Este modo permite comparar un lote y construir un informe \u00fanico. Los nombres son etiquetas del proyecto: ren\u00f3mbralos para seguir las explicaciones.<\/p><p>Hemos elegido Code para mantener visibles las reglas de validaci\u00f3n y conservar tambi\u00e9n los registros problem\u00e1ticos. No es la \u00fanica implementaci\u00f3n posible: una combinaci\u00f3n de Edit Fields, IF, Remove Duplicates y Aggregate puede repartir el trabajo entre m\u00e1s nodos. Aqu\u00ed el objetivo es comprender una pol\u00edtica completa antes de conectar servicios.<\/p><figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/n8nfacil.com\/wp-content\/uploads\/2026\/11\/12-contactos-flujo.jpg\" alt=\"Workflow de calidad de contactos ejecutado con seis registros ficticios.\" width=\"1101\" height=\"874\" loading=\"lazy\"\/><figcaption>Workflow de calidad de contactos ejecutado con seis registros ficticios.<\/figcaption><\/figure><h2>2. Introduce un lote con problemas diferentes<\/h2><p>Pega este c\u00f3digo en Datos de ejemplo. No arregles los espacios ni a\u00f1adas el correo que falta: necesitamos conservar esos casos para observar la clasificaci\u00f3n.<\/p><pre><code>return [\n  {\n    \"id\": \"C1\",\n    \"nombre\": \" Ana \",\n    \"email\": \" ANA@EXAMPLE.COM \"\n  },\n  {\n    \"id\": \"C2\",\n    \"nombre\": \"Ana repetida\",\n    \"email\": \"ana@example.com\"\n  },\n  {\n    \"id\": \"C3\",\n    \"nombre\": \"Luis\",\n    \"email\": \"luis@example.com\"\n  },\n  {\n    \"id\": \"C4\",\n    \"nombre\": \"Sin correo\"\n  },\n  {\n    \"id\": \"C5\",\n    \"nombre\": \"Correo incompleto\",\n    \"email\": \"ana@\"\n  },\n  {\n    \"id\": \"C6\",\n    \"nombre\": \"   \",\n    \"email\": \"otra@example.com\"\n  }\n].map(json =&gt; ({json}));<\/code><\/pre><p>Cada entrada tiene un id que permite localizarla sin depender del nombre. El caso C2 comparte correo con C1, C4 no trae email, C5 contiene una direcci\u00f3n incompleta y C6 tiene un nombre formado por espacios. Una automatizaci\u00f3n \u00fatil debe explicar qu\u00e9 ocurri\u00f3 con todos ellos.<\/p><h2>3. Normaliza, comprueba y clasifica<\/h2><p>Pega lo siguiente en Evaluar registros. El Set vistos se crea al empezar esta ejecuci\u00f3n y solo recibe correos de registros que ya han superado las comprobaciones. As\u00ed, una fila incompleta no reserva un correo e impide aceptar otra fila posterior correcta.<\/p><pre><code>const vistos = new Set();\nreturn $input.all().map(item =&gt; {\n  const original = item.json;\n  const nombre = typeof original.nombre === 'string' ? original.nombre.trim() : '';\n  const email = typeof original.email === 'string' ? original.email.trim().toLowerCase() : '';\n  const motivos = [];\n  if (!nombre) motivos.push('nombre_ausente');\n  if (!\/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$\/.test(email)) motivos.push('formato_email');\n  let estado = 'valido';\n  if (motivos.length) estado = 'revisar';\n  else if (vistos.has(email)) estado = 'duplicado';\n  else vistos.add(email);\n  return {json: {id: original.id, nombre, email, estado, motivos}};\n});<\/code><\/pre><p>El orden de las reglas importa: primero revisamos nombre y formato; despu\u00e9s buscamos repetici\u00f3n. La primera fila v\u00e1lida con ese correo queda como v\u00e1lida y las siguientes como duplicadas. No fusionamos nombres ni elegimos autom\u00e1ticamente \u201cla ficha m\u00e1s reciente\u201d, porque no tenemos una fecha fiable para hacerlo.<\/p><p>La expresi\u00f3n regular es deliberadamente sencilla. Descarta errores habituales como un n\u00famero usado como correo o una direcci\u00f3n sin parte de dominio, pero no implementa toda la especificaci\u00f3n del correo electr\u00f3nico. El array motivos conserva una explicaci\u00f3n que podr\u00eda mostrarse en una revisi\u00f3n manual.<\/p><h2>4. Genera un informe sin perder filas<\/h2><p>En Informe del lote utiliza este c\u00f3digo. La salida es un elemento con contadores y listas; no seis elementos separados. Un consumidor posterior tendr\u00eda que seleccionar una lista y convertir sus entradas en elementos si necesita procesarlas una a una.<\/p><pre><code>const filas = $input.all().map(item =&gt; item.json);\nconst validos = filas.filter(f =&gt; f.estado === 'valido');\nconst duplicados = filas.filter(f =&gt; f.estado === 'duplicado');\nconst revisar = filas.filter(f =&gt; f.estado === 'revisar');\nreturn [{json: {recibidos: filas.length, total_validos: validos.length,\n  total_duplicados: duplicados.length, total_revisar: revisar.length,\n  validos, duplicados, revisar}}];<\/code><\/pre><h2>5. Comprueba los resultados antes de conectar un destino<\/h2><figure class=\"wp-block-table\"><table><thead><tr><th>Grupo<\/th><th>Resultado del lote de ejemplo<\/th><\/tr><\/thead><tbody><tr><td>Recibidos<\/td><td>6<\/td><\/tr><tr><td>V\u00e1lidos<\/td><td>2: C1 y C3<\/td><\/tr><tr><td>Duplicados<\/td><td>1: C2<\/td><\/tr><tr><td>Para revisar<\/td><td>3: C4, C5 y C6<\/td><\/tr><\/tbody><\/table><\/figure><p>Comprueba la igualdad 6 = 2 + 1 + 3. Esta conciliaci\u00f3n ayuda a detectar registros perdidos entre etapas. Abre validos y verifica que el correo de Ana sale como ana@example.com. En duplicados debe figurar C2; no basta con que el contador diga uno.<\/p><h2>Casos l\u00edmite que probamos<\/h2><p>Tambi\u00e9n ejecutamos una variante con un primer registro sin nombre, otro posterior correcto con el mismo correo, un duplicado normalizado y un email num\u00e9rico. El resultado fue un v\u00e1lido, un duplicado y dos para revisar. El contacto correcto sigui\u00f3 siendo aceptado: el incompleto anterior no hab\u00eda reservado su correo. Al repetir el lote original se obtuvo el mismo informe, confirmando que el Set no conserva historial entre ejecuciones.<\/p><h2>Lo que este proyecto no resuelve<\/h2><p>Si el mismo contacto vuelve ma\u00f1ana, se volver\u00e1 a considerar v\u00e1lido dentro del nuevo lote. Para evitar duplicados entre ejecuciones necesitas un destino persistente y una clave estable; no uses una variable en memoria como si fuera una base de datos. Adem\u00e1s, resolver conflictos entre nombres, fechas y fuentes exige una pol\u00edtica de actualizaci\u00f3n expl\u00edcita.<\/p><p>Un lote sin elementos puede detener el recorrido antes del informe: aqu\u00ed no hemos verificado un origen vac\u00edo dentro de n8n. Tampoco se ha medido rendimiento con miles de registros. No conectes el resultado a un env\u00edo masivo hasta revisar permisos, bajas, errores del proveedor y tratamiento de datos personales.<\/p><h2>C\u00f3mo encaja con los tutoriales anteriores<\/h2><p>Si la normalizaci\u00f3n te resulta nueva, empieza por <a href=\"https:\/\/n8nfacil.com\/limpiar-datos-n8n-edit-fields\/\">limpiar datos con Edit Fields<\/a>. Para comparar enfoques, revisa <a href=\"https:\/\/n8nfacil.com\/eliminar-duplicados-n8n-email\/\">Remove Duplicates<\/a>. Un posible siguiente paso es recibir los registros desde un <a href=\"https:\/\/n8nfacil.com\/webhook-n8n-formulario\/\">Webhook<\/a>, manteniendo separada la recepci\u00f3n de la validaci\u00f3n. Este descargable todav\u00eda utiliza el disparador manual.<\/p><p>Consulta la <a href=\"https:\/\/docs.n8n.io\/integrations\/builtin\/core-nodes\/n8n-nodes-base.code\/\">documentaci\u00f3n oficial del nodo Code<\/a> para sus modos de ejecuci\u00f3n y la <a href=\"https:\/\/docs.n8n.io\/data\/data-structure\/\">estructura de datos de n8n<\/a> para entender los objetos con una propiedad json. Los c\u00f3digos de esta gu\u00eda son propios del proyecto.<\/p><figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/n8nfacil.com\/wp-content\/uploads\/2026\/11\/12-contactos-resultado.jpg\" alt=\"El informe separa dos contactos v\u00e1lidos, un duplicado y tres para revisar.\" width=\"1101\" height=\"874\" loading=\"lazy\"\/><figcaption>El informe separa dos contactos v\u00e1lidos, un duplicado y tres para revisar.<\/figcaption><\/figure><h2>Descarga el proyecto para repetir la pr\u00e1ctica<\/h2><p><a href=\"https:\/\/n8nfacil.com\/wp-content\/uploads\/2026\/11\/12-calidad-contactos.zip\">Descargar workflow y archivos de pr\u00e1ctica en ZIP<\/a>. Incluye el JSON de n8n, los c\u00f3digos de los nodos, instrucciones y resultados de las pruebas. No incluye la base de datos de la instalaci\u00f3n ni credenciales.<\/p><p><strong>Autor: Javier Fern\u00e1ndez.<\/strong> Soy estudiante y comparto lo que aprendo con proyectos de pr\u00e1ctica. Las pruebas descritas utilizan datos ficticios. <a href=\"https:\/\/n8nfacil.com\/sobre\/\">Conoce el proyecto<\/a> o <a href=\"https:\/\/n8nfacil.com\/contacto\/\">comunica un error<\/a> indicando el paso y la versi\u00f3n de n8n.<\/p>","protected":false},"excerpt":{"rendered":"<p>Conecta limpieza, validaci\u00f3n, duplicados e informe en un solo proyecto local. Conserva los registros que requieren revisi\u00f3n y comprueba los resultados.<\/p>","protected":false},"author":1,"featured_media":330,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-324","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-datos-expresiones"],"_links":{"self":[{"href":"https:\/\/n8nfacil.com\/en\/wp-json\/wp\/v2\/posts\/324","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/n8nfacil.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/n8nfacil.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/n8nfacil.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/n8nfacil.com\/en\/wp-json\/wp\/v2\/comments?post=324"}],"version-history":[{"count":2,"href":"https:\/\/n8nfacil.com\/en\/wp-json\/wp\/v2\/posts\/324\/revisions"}],"predecessor-version":[{"id":334,"href":"https:\/\/n8nfacil.com\/en\/wp-json\/wp\/v2\/posts\/324\/revisions\/334"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/n8nfacil.com\/en\/wp-json\/wp\/v2\/media\/330"}],"wp:attachment":[{"href":"https:\/\/n8nfacil.com\/en\/wp-json\/wp\/v2\/media?parent=324"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/n8nfacil.com\/en\/wp-json\/wp\/v2\/categories?post=324"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/n8nfacil.com\/en\/wp-json\/wp\/v2\/tags?post=324"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}