1
2 Comments

How to suggest email typo corrections?

I have forms that get 100s of submissions with peoples name and email every day. They all get a confirmation email after submitting.

I'm surprised lot of people can't seem to spell their own email address: almost 1% of the submissions have a non-existing email address because people make a typo. Think [email protected] instead of [email protected].

I added mailcheck to check typos in popular domains like gmail.com.
That helps, although there are still people who make mistakes this way.

However, most of the non-existing emails are people who misspell their name, like [email protected]. Since they also enter their name, I could suggest to John Doe that his email might be [email protected] instead.

Does anything exist for this yet?
If not, how could I implement something like this?

Thanks!

  1. 2

    I don't know anything doing this.

    But as you have the name asked in the same form, you can try to search for it in the email address and compute the distance between substrings of the email address and the name.

    If you find a word that is only one letter away, just warn the user about a possible typo.

    But I would not block the form submission, just a small warning.

  2. 1

    I put something quick and dirty together that seems to be doing the trick:

    const splitCharsRegex = /[_. ,-]/;
    const split = (str) => str.split(splitCharsRegex).map(s => s.toLowerCase());
    
    // Source: https://gist.github.com/andrei-m/982927/0efdf215b00e5d34c90fdc354639f87ddc3bd0a5
    const levenshteinDistance = function(a, b) {
    	if(a.length == 0) return b.length;
    	if(b.length == 0) return a.length;
    
    	// swap to save some memory O(min(a,b)) instead of O(a)
    	if(a.length > b.length) {
    		var tmp = a;
    		a = b;
    		b = tmp;
    	}
    
    	var row = [];
    	// init the row
    	for(var i = 0; i <= a.length; i++){
    		row[i] = i;
    	}
    
    	// fill in the rest
    	for(var i = 1; i <= b.length; i++){
    		var prev = i;
    		for(var j = 1; j <= a.length; j++){
    			var val;
    			if(b.charAt(i-1) == a.charAt(j-1)){
    				val = row[j-1]; // match
    			} else {
    				val = Math.min(row[j-1] + 1, // substitution
    						prev + 1,     // insertion
    						row[j] + 1);  // deletion
    			}
    			row[j - 1] = prev;
    			prev = val;
    		}
    		row[a.length] = prev;
    	}
    
    	return row[a.length];
    }
    
    // Source: https://stackoverflow.com/questions/40654895/javascript-generating-all-permutations-of-an-array
    const combo = (c) => {
    	let r = [],
    			len = c.length,
    			tmp = [];
    
    	function nodup() {
    		var got = {};
    		for (var l = 0; l < tmp.length; l++) {
    			if (got[tmp[l]]) return false;
    			got[tmp[l]] = true;
    		}
    		return true;
    	}
    	function iter(col) {
    		let l, rr;
    		if (col === len) {
    			if (nodup()) {
    				rr = [];
    				for (l = 0; l < tmp.length; l++)
    					rr.push(c[tmp[l]]);
    				r.push(rr);
    			}
    		} else {
    			for (l = 0; l < len; l ++) {
    				tmp[col] = l;
    				iter(col +1);
    			}
    		}
    	}
    	iter(0);
    	return r;
    }
    
    const getSuggestion = (email = '', name = '') => {
    	const username = email.split('@')[0];
        const emailWords = split(username) || [];
        const nameWords = split(name) || [];
    
        // Check complete username <> name, in different orders
    	if (!username.match(splitCharsRegex)) {
    		const allPossibleOrdersOfNameWords = combo(nameWords);
    		for (let words of allPossibleOrdersOfNameWords) {
    			if (levenshteinDistance(username.toLocaleLowerCase(), words.join('')) === 1) {
    				return email.replace(username, words.join(''));
    			}
    		}
    	}
    
        // Check each part of the username
        for (let emailWord of emailWords) {
            const nameWord = nameWords.find(w => levenshteinDistance(emailWord, w) === 1);
            if (nameWord) return email.replace(emailWord, nameWord);
        }
    }
    
    console.log(getSuggestion('[email protected]', 'John Doe')); // returns "[email protected]"
Trending on Indie Hackers
How I grew a side project to 100k Unique Visitors in 7 days with 0 audience 49 comments Competing with Product Hunt: a month later 33 comments Why do you hate marketing? 29 comments My Top 20 Free Tools That I Use Everyday as an Indie Hacker 16 comments $15k revenues in <4 months as a solopreneur 14 comments Use Your Product 13 comments