Este artículo también está disponible en: English (Inglés)

Anteriormente en este blog hemos visto cómo sugerir el email a nuestro usuario.
Este post formará parte de una serie de artículos que tratan sobre la validación del campo del correo electrónico en nuestros formularios web.
Siempre merece la pena recalcar la importancia de validar los correos de nuestros usuarios, como hemos comentado en anteriores ocasiones. Y es que en la mayoría de casos va a suponer nuestro método de contacto principal con nuestro cliente.
A la hora de revisar los correos que nos han proporcionado los usuarios, es habitual encontrarse con erratas en los correos tipo del tipo: hotmeil.com o gmial.com, que suelen ser pequeñas erratas por parecidos fonéticos o por proximidad de las letras en el teclado.
En otros tiempos, podíamos corregir estos errores a mano o filtrar nuestra base de datos encontrando este tipo de fallos del usuario. Pero hoy en día, por las regulaciones en el campo de protección de datos, ya no es tan fácil.
Y algunos podéis pensar “Oye! Yo es que lo corrijo a mano y tengo 0 problemas, hermano”. Pues seguramente estés haciendo algo ilegal, hermano.
No soy un experto jurídico, pero sé esto: Si el usuario ha introducido mal su información de contacto, has perdido a un cliente.
No tienes el derecho a corregir un error en el correo electrónico de tus clientes por tonto que sea ese error y teóricamente, tampoco puedes contactar con el cliente por otra vía que no haya autorizado.
Así que vamos a ver cómo podemos ayudar a que el usuario se dé cuenta de los errores que ha cometido a la hora de escribir el email.
Sugeriendo un cambio
Lo que vamos a conseguir al final de este post, es tener un campo de correo electrónico que cuando el usuario haya introducido su supuesta dirección de email se compruebe si la parte del dominio se parece mucho al de algún proveedor de correos habitual. Y que en el caso de que se parezca mucho a uno de estos dominios, le sugiera al usuario cambiar el correo que ha introducido por una con el error corregido.

Básicamente que si ponen xyz@hotmsil.com queremos que le sugiera xyz@hotmail.com y lo mismo para otros proveedores de correo.
Aquí en Sonneil nos encanta el MVC, así que aquí va cómo tendrían que verse el formulario, el script y los estilos, para conseguir el funcionamiento básico de corrección de errores.
Formulario
El único requisito del formulario es que tenga un input de tipo email.
<form class="" id="contact-form" method="POST"
enctype="application/x-www-form-urlencoded">
<div class="form-group">
<input aria-describedby="name"
class="form-control" name="name"
id="name" placeholder="Name" type="text" required>
</div>
<div class="form-group">
<input aria-describedby="email" class="form-control"
id="email" name="email" placeholder="E-mail" type="email" required>
</div>
<button type="submit">Send</button>
</form>
Script
Llegó el momento de darle lógica, vamos a empezar por importar jQuery.
Y creamos el archivo script.js
que importaremos en en nuestro HTML.
A continuación se ve cómo tiene que quedar el <head>
de tu HTML para importar jQuery y tu nuevo documento script.js
<head>
<script src="https://code.jquery.com/jquery-3.4.1.min.js" crossorigin="anonymous"></script>
<script src="./scripts.js"></script>
</head>
Con esto está todo preparado para añadirle la funcionalidad que buscamos.
Queremos que cuando el usuario haya escrito su correo electrónico, el script revise lo que acaba de introducir el usuario, compruebe si cree que hay un error en el dominio y en el caso de que lo haya, sugerirle al usuario una corrección al cual le pueda dar clic para corregir el campo.
Usaremos un plugin de jQuery que nos facilitará mucho el desarrollo: mailcheck
Para usarlo, importaremos el mailcheck a nuestro proyecto. En nuestro caso hemos copiado el script minificado.
El plugin hace la mayoría del trabajo, pero nos toca a nosotros hacer que se muestre la sugerencia y se reemplace cuando el usuario la seleccione.
Vamos a crear la función suggestionEmail
al cual llamaremos para comprobar si hay correcciones posibles. Dentro de esta función llamaremos al método mailcheck
en la referencia del input del email.
El método mailcheck
tiene dos callbacks:
suggested
: Se llamará cuando el plugin crea que hay un error. Aquí es donde tenemos que controlar cómo mostramos la sugerencia al usuario.empty
: Se llamará cuando el plugin crea que no hay error o no tenga una corrección posible. Aquí deberíamos quitar cualquier sugerencia que hayamos hecho.
Basta ya de hablar de código y vamos a verlo:
/* Email correction */
/*! mailcheck v1.1.2 @licence MIT */var Mailcheck={domainThreshold:2,secondLevelThreshold:2,topLevelThreshold:2,defaultDomains:["msn.com","bellsouth.net","telus.net","comcast.net","optusnet.com.au","earthlink.net","qq.com","sky.com","icloud.com","mac.com","sympatico.ca","googlemail.com","att.net","xtra.co.nz","web.de","cox.net","gmail.com","ymail.com","aim.com","rogers.com","verizon.net","rocketmail.com","google.com","optonline.net","sbcglobal.net","aol.com","me.com","btinternet.com","charter.net","shaw.ca"],defaultSecondLevelDomains:["yahoo","hotmail","mail","live","outlook","gmx"],defaultTopLevelDomains:["com","com.au","com.tw","ca","co.nz","co.uk","de","fr","it","ru","net","org","edu","gov","jp","nl","kr","se","eu","ie","co.il","us","at","be","dk","hk","es","gr","ch","no","cz","in","net","net.au","info","biz","mil","co.jp","sg","hu","uk"],run:function(a){a.domains=a.domains||Mailcheck.defaultDomains,a.secondLevelDomains=a.secondLevelDomains||Mailcheck.defaultSecondLevelDomains,a.topLevelDomains=a.topLevelDomains||Mailcheck.defaultTopLevelDomains,a.distanceFunction=a.distanceFunction||Mailcheck.sift4Distance;var b=function(a){return a},c=a.suggested||b,d=a.empty||b,e=Mailcheck.suggest(Mailcheck.encodeEmail(a.email),a.domains,a.secondLevelDomains,a.topLevelDomains,a.distanceFunction);return e?c(e):d()},suggest:function(a,b,c,d,e){a=a.toLowerCase();var f=this.splitEmail(a);if(c&&d&&-1!==c.indexOf(f.secondLevelDomain)&&-1!==d.indexOf(f.topLevelDomain))return!1;var g=this.findClosestDomain(f.domain,b,e,this.domainThreshold);if(g)return g==f.domain?!1:{address:f.address,domain:g,full:f.address+"@"+g};var h=this.findClosestDomain(f.secondLevelDomain,c,e,this.secondLevelThreshold),i=this.findClosestDomain(f.topLevelDomain,d,e,this.topLevelThreshold);if(f.domain){g=f.domain;var j=!1;if(h&&h!=f.secondLevelDomain&&(g=g.replace(f.secondLevelDomain,h),j=!0),i&&i!=f.topLevelDomain&&""!==f.secondLevelDomain&&(g=g.replace(new RegExp(f.topLevelDomain+"$"),i),j=!0),j)return{address:f.address,domain:g,full:f.address+"@"+g}}return!1},findClosestDomain:function(a,b,c,d){d=d||this.topLevelThreshold;var e,f=1/0,g=null;if(!a||!b)return!1;c||(c=this.sift4Distance);for(var h=0;h<b.length;h++){if(a===b[h])return a;e=c(a,b[h]),f>e&&(f=e,g=b[h])}return d>=f&&null!==g?g:!1},sift4Distance:function(a,b,c){if(void 0===c&&(c=5),!a||!a.length)return b?b.length:0;if(!b||!b.length)return a.length;for(var d=a.length,e=b.length,f=0,g=0,h=0,i=0,j=0,k=[];d>f&&e>g;){if(a.charAt(f)==b.charAt(g)){i++;for(var l=!1,m=0;m<k.length;){var n=k[m];if(f<=n.c1||g<=n.c2){l=Math.abs(g-f)>=Math.abs(n.c2-n.c1),l?j++:n.trans||(n.trans=!0,j++);break}f>n.c2&&g>n.c1?k.splice(m,1):m++}k.push({c1:f,c2:g,trans:l})}else{h+=i,i=0,f!=g&&(f=g=Math.min(f,g));for(var o=0;c>o&&(d>f+o||e>g+o);o++){if(d>f+o&&a.charAt(f+o)==b.charAt(g)){f+=o-1,g--;break}if(e>g+o&&a.charAt(f)==b.charAt(g+o)){f--,g+=o-1;break}}}f++,g++,(f>=d||g>=e)&&(h+=i,i=0,f=g=Math.min(f,g))}return h+=i,Math.round(Math.max(d,e)-h+j)},splitEmail:function(a){a=null!==a?a.replace(/^\s*/,"").replace(/\s*$/,""):null;var b=a.split("@");if(b.length<2)return!1;for(var c=0;c<b.length;c++)if(""===b[c])return!1;var d=b.pop(),e=d.split("."),f="",g="";if(0===e.length)return!1;if(1==e.length)g=e[0];else{f=e[0];for(var h=1;h<e.length;h++)g+=e[h]+".";g=g.substring(0,g.length-1)}return{topLevelDomain:g,secondLevelDomain:f,domain:d,address:b.join("@")}},encodeEmail:function(a){var b=encodeURI(a);return b=b.replace("%20"," ").replace("%25","%").replace("%5E","^").replace("%60","`").replace("%7B","{").replace("%7C","|").replace("%7D","}")}};"undefined"!=typeof module&&module.exports&&(module.exports=Mailcheck),"function"==typeof define&&define.amd&&define("mailcheck",[],function(){return Mailcheck}),"undefined"!=typeof window&&window.jQuery&&!function(a){a.fn.mailcheck=function(a){var b=this;if(a.suggested){var c=a.suggested;a.suggested=function(a){c(b,a)}}if(a.empty){var d=a.empty;a.empty=function(){d.call(null,b)}}a.email=this.val(),Mailcheck.run(a)}}(jQuery);
/* Form code */
jQuery(document).ready( function () {
function suggestionEmail(element) {
element.mailcheck({
suggested: function(element, suggestion) {
if(document.getElementById("hint")) document.getElementById("hint").remove();
var hint = document.createElement("div");
hint.setAttribute("id", "hint");
hint.style.height = 0;
var html = `<p>
<span>
${suggestion.full}
</span> ?
</p>`;
hint.innerHTML = html;
hint.addEventListener("click", () => {element[0].value = suggestion.full; document.getElementById("hint").remove();});
element.after(hint);
},
empty: function(element) {
if(document.getElementById("hint")) document.getElementById("hint").remove();
}
})
}
/* Client email validation */
jQuery("#contact-form input[type='email'].form-control").each(function () {
jQuery(this).blur(function() {
suggestionEmail(jQuery(this));
})
})
});
Como podéis ver en el código anterior, en suggested
hemos creado un elemento <p>
que muestre la corrección del email y la lógica que reemplaza el texto del input. Las sugerencias del plugin se acceden a través del segundo parámetro del callback suggested
, el cual es un objeto con tres atributos: address (correo antes del @), dominio (el dominio sugerido) y full (que es el correo completo).
En el callback empty
hemos añadido que si existe una sugerencia en el DOM la elimine, ya que si está en empty
significa que ya se ha corregido el error.
Si queréis más customización, como la de añadir vuestra propia lista de dominios, diferenciar sugerencias por niveles de dominio, limitar la longitud de las sugerencias, etc. podéis consultar la documentación del plugin.
Estilos
Para acabar vamos a añadirle unos estilos simples, es importante controlar que la sugerencia del email se muestre correctamente en nuestro formulario. Nosotros somos los que decidimos como es el elemento de la sugerencia, así que hay infinitas maneras de hacerlo. Aquí le hemos puesto un id=”hint”
a nuestro elemento sugerencia, acceder a él facilmente.
Recomiendo ponerle un line-height:0
, ya que estamos introduciendo un elemento en medio de una página que seguramente ya esté estilizada y lo último que queremos es que la sugerencia descuadre el bonito aspecto de nuestra web.
Así he dejado yo el estilo del elemento sugerencia, directamente en la definición literal del elemento en script:
var html = `<p style="cursor: pointer; line-height:0;" class="small p-2 pb-0 m-0">
<span class="btn-link">
${suggestion.full}
</span> ?
</p>`;
¡Y eso sería todo! Ya tenemos un campo de correo que corrige a nuestros usuarios.

Encuentra el código completo de este proyecto en nuestro Github.
Hasta pronto muchach@s ✌️