Home > Uncategorized > Enhanced email validation using #DNS #MX

Enhanced email validation using #DNS #MX

email

If you have a sign-up form, and you are collecting user’s email addresses, then you really want to cut down on the number of typos. I’ve seen as many as 5% of users mistyping “@gmail.com” as “@gmail.con, @gmail.co, @gmai.com, and @gmail.xom etc.”

Many of these email addresses pass basic regex checks, it’s “Gmail.co” is in the correct format for a domain name, but alas, your user will never be able to re-log in.

So, instead of only relying on regexes, you can also use a DNS MX lookup, that can check if there are mail exchanger(s) associated with the domain. This means that “@gmail.com” will work, but “@gmail.co” won’t

Firstly, we have to delve into how to perform a DNS MX lookup in C#, which is a UDP request sent over port 53 to a DNS server, in this case 8.8.8.8, which is Google’s public DNS resolver.

Here’s the class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;

public static class Dns
{
public static IEnumerable<string> MxLookup(string domain)
{
const string strDns = “8.8.8.8”; // Google DNS
var udpClient = new UdpClient(strDns, 53);
// SEND REQUEST——————–
var list = new List<byte>();
list.AddRange(new byte[] { 88, 89, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 });
var tmp = domain.Split(‘.’);
foreach (string s in tmp)
{
list.Add(Convert.ToByte(s.Length));
var chars = s.ToCharArray();
list.AddRange(chars.Select(c => Convert.ToByte(Convert.ToInt32(c))));
}
list.AddRange(new byte[] { 0, 0, Convert.ToByte(15), 0, 1 });
var req = new byte[list.Count];
for (var i = 0; i < list.Count; i++) { req[i] = list[i]; }
udpClient.Send(req, req.Length);
// RECEIVE RESPONSE————–
IPEndPoint ep = null;
var receiveBuffer = udpClient.Receive(ref ep);
udpClient.Close();
var resp = new int[receiveBuffer.Length];
for (var i = 0; i < resp.Length; i++)
resp[i] = Convert.ToInt32(receiveBuffer[i]);
var status = resp[3];
if (status != 128) return null; // throw new Exception(string.Format(“{0}”, status));
var answers = resp[7];
if (answers == 0) return null; // throw new Exception(“No results”);
var pos = domain.Length + 18;
var lRecords = new List<string>();
while (answers > 0)
{
pos += 14; //offset
var str = GetMxRecord(resp, pos, out pos);
lRecords.Add(str);
answers–;
}
return lRecords;
}

private static string GetMxRecord(int[] resp, int start, out int pos)
{
StringBuilder sb = new StringBuilder();
int len = resp[start];
while (len > 0)
{
if (len != 192)
{
if (sb.Length > 0) sb.Append(“.”);
for (int i = start; i < start + len; i++)
sb.Append(Convert.ToChar(resp[i + 1]));
start += len + 1;
len = resp[start];
}
if (len != 192) continue;
var newPosition = resp[start + 1];
if (sb.Length > 0) sb.Append(“.”);
sb.Append(GetMxRecord(resp, newPosition, out newPosition));
start++;
break;
}
pos = start + 1;
return sb.ToString();
}
}

[Credit due to Christian Salway @ccsalway for this code]

This when called as Dns.MxLookup(“gmail.com”), would return a list of strings as follows;

"gmail-smtp-in.l.google.com",
"alt4.gmail-smtp-in.l.google.com",
"alt1.gmail-smtp-in.l.google.com",
"alt2.gmail-smtp-in.l.google.com",
"alt3.gmail-smtp-in.l.google.com"

These correspond to the mail exchange servers used by gmail, and indicate that the domain can receive email, otherwise, this function returns null.

Now, lets create an ASP.NET page that will act as a handler for an Ajax call to validate an email address as follows;

using System;
using System.Collections.Generic;
using Newtonsoft.Json;

public partial class ajax_ValidateEmail : System.Web.UI.Page
{
private class ResponseClass
{
public bool success { get; set; }
public string error { get; set; }
public IEnumerable<string> information { get; set; }
}

protected void Page_Load(object sender, EventArgs e)
{
var response = new ResponseClass();
var email = Request.QueryString[“email”];
if (string.IsNullOrEmpty(email))
{
response.error = “Need on email on querystring”;
}
else
{
var idxAt = email.IndexOf(“@”, StringComparison.CurrentCulture);
if (idxAt == -1)
{
response.error = “Invalid email address”;
}
else
{
var domain = email.Substring(idxAt+1);
var mx = Dns.MxLookup(domain);
if (mx == null)
{
response.error = “Invalid domain”;
}
else
{
response.success = true;
response.information = mx;
}
}
}
var json = JsonConvert.SerializeObject(response, Formatting.Indented);
Response.ContentType = “application/json”;
Response.Write(json);
}
}

This will respond with the following Json in the case of success;

{
  "success": true,
  "error": null,
  "information": [
    "gmail-smtp-in.l.google.com",
    "alt4.gmail-smtp-in.l.google.com",
    "alt1.gmail-smtp-in.l.google.com",
    "alt2.gmail-smtp-in.l.google.com",
    "alt3.gmail-smtp-in.l.google.com"
  ]
}

And, in the case of failure;

{
  "success": false,
  "error": "Invalid domain",
  "information": null
}

This can then be called from Javascript (jquery) as follows;

var strEmail = $(“#tbEmail”).val();
$.get(“/ajax/ValidateEmail.aspx?email=” + strEmail,
function(response) {
if (!response.success) {
$(“#fgEmail”).addClass(“has-error”);
} else {
$(“#fgEmail”).removeClass(“has-error”);
}
});

You can go a step further and prevent the form submission, at the moment, I’m just relaying user feedback, and see what happens.

To see this live, see https://www.regcheck.org.uk

 

Advertisements
Categories: Uncategorized
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: