There are various ways to validate an email address from .NET, the choice of which one to use is based on how restrictive you wish to be to your end user. This articles details the following methods of email validation:
- Email format validation
- Domain name validation
- Mail server validation
The simplest is the email format validation as it merely checks the format of the supplied email address and not if any of it is valid, the slightly more complicated is the domain name validation is where the domain name after the @ sign is extracted and the domain is checked to see if it exists. The most complicated is the SMTP lookup where the actual mail servers are contacted and communicated with in order to see if the email address is valid. A worthy note is that as each version becomes more complicated you are also increasing runtime and also the chance of a false negative, ie. that a valid email address will flagged as invalid.
Email format validation
This version actually uses two stages, firstly there is the regex expression, if that passes then it falls back to the built in MailAddress class within the System.Net.Mail namespace. This is because occasionally email addresses will pass the regex expression but were not able to be sent via the .NET email functions. The concept of doing the regex first is to catch all obviously wrong email addresses before proceeding onto the more complicated .NET version.
Public Shared Function ValidateEmail(ByVal EmailString As String) As Boolean ValidateEmail = True Dim RegexPattern As String = "^([a-zA-Z0-9_-.]+)@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.)|(([a-zA-Z0-9-]+.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(]?)$" Dim Re As System.Text.RegularExpressions.Regex = New System.Text.RegularExpressions.Regex(RegexPattern) If Not (Re.IsMatch(EmailString)) Then ValidateEmail = False Else Try Dim EmailAddress As System.Net.Mail.MailAddress = New System.Net.Mail.MailAddress(EmailString) Catch fex As FormatException ValidateEmail = False End Try End If End Sub
Domain name validation
To validate a domain name we can use the built-in Dns class in the System.Net namespace, it has a method GetHostByName which given a domain name will attempt to resolve it. If it is unable to then a SocketException is thrown, this functionality can be implemented in the following function:
Public Function ValidateDomainName(byVal DomainName as String) As Integer ' Default the return code to 1, this signifys a valid domain name ValidateDomainName = 1 Try Dim HostEntry as IPHostEntry = Dns.GetHostByName(DomainName) Catch (ane as ArgumentNullException) ' The domain name is a null reference ValidateDomainName = -1 Catch (aoore as ArgumentOutOfRangeException) ' The length of the domain name is greater than 126 characters ValidateDomainName = -2 Catch (se as SocketException) ' An error occured whilst trying to resolve the domain name ValidateDomainName = -3 End Try End Function
Mail server validation
Firstly in order to communicate with the mail server we will need to write a series of utility functions, which are listed below:
Private Shared Function GetData(ByRef NetworkStream As NetworkStream) As String Dim Buffer(1024) As Byte Dim Response As String = "" Dim Stream As Integer = NetworkStream.Read(Buffer, 0, 1024) If Stream > 0 Then Response = Encoding.ASCII.GetString(Buffer, 0, 1024) End If Return Response End Function Private Shared Function SendData(ByRef NetworkStream As NetworkStream, ByVal ToSend As String) As String Dim Array() As Byte = Encoding.ASCII.GetBytes(ToSend.ToCharArray) NetworkStream.Write(Array, 0, Array.Length()) Dim Response As String = GetData(NetworkStream) Return Response End Function Private Shared Function ValidResponse(ByVal Result As String) As Boolean ValidResponse = False Dim First As Integer If Result.Length > 1 Then First = CType(Result.Substring(0, 1), Integer) If First < 3 Then ValidResponse = True End If End If End Function Private Shared Function TalkToServer(ByVal NetworkStream As NetworkStream, ByVal ToSend As String) As String Dim Response As String = SendData(NetworkStream, ToSend) Return Response End Function Private Shared Function NSLookup(ByVal Domain As String) As String ' We are going to run the nslookup command and parse the response using an Regex to find the mail server for the specified domain ' ' Below is the example output for google.co.uk 'Non-authoritative answer: 'google.co.uk MX preference = 10, mail exchanger = smtp3.google.com 'google.co.uk MX preference = 10, mail exchanger = smtp4.google.com 'google.co.uk MX preference = 10, mail exchanger = smtp1.google.com 'google.co.uk MX preference = 10, mail exchanger = smtp2.google.com ' Dim ProcessStartInfo As New ProcessStartInfo() ProcessStartInfo.UseShellExecute = False ProcessStartInfo.RedirectStandardInput = True ProcessStartInfo.RedirectStandardOutput = True ProcessStartInfo.FileName = "nslookup" ProcessStartInfo.Arguments = "-type=MX " + Domain.ToUpper.Trim Dim Process As Process = Process.Start(ProcessStartInfo) Dim StreamOut As StreamReader = Process.StandardOutput Dim RegExpression As Regex = New Regex("mail exchanger = (?<server>[^\s]+)") ' Return the blank string if it is not found Dim MailServer As String = "" Dim Response As String = "" ' Go through the command response to find the mx server Do While (StreamOut.Peek() > -1) Response = StreamOut.ReadLine() Dim AMatch As Match = RegExpression.Match(Response) If (AMatch.Success) Then MailServer = AMatch.Groups("server").Value Exit Do End If Loop Return MailServer End Function
We can now use these functions to find out the mail server address and to communicate with it. The CheckEmailAddress function below uses the functions to talk to the mail server and determine if the supplied email address is in fact valid. It will return the following status code as an integer to indicate its result:
- 1 Valid email address
- -1 Invalid response from the SMTP server
- -2 A general communication fault
- -3 No mail server found
- -4 No doman name specified
Public Shared Function CheckEmailAddress(ByVal EmailAddress As String) As Integer ' Setup the fixed variables Dim RemoteAddress As String = "sgc2000.co.uk" Dim FromAddress As String = "<do-not-reply@" & RemoteAddress + ">" Dim ToAddress As String = "<" + EmailAddress + ">" ' Seperate domain name from user name Dim SplitAddress As String() = EmailAddress.Split(CType("@", Char)) If SplitAddress.Length >= 2 Then Dim MailServer As String = NSLookup(SplitAddress(1)) ' If mail server is blank then fail otherwise continue If MailServer <> "" Then 'Create Object as late as possible Dim TcpClient As New TcpClient() Try ' Set connection based on load TcpClient.SendTimeout = 3000 ' Connecting on SMTP port TcpClient.Connect(MailServer, 25) ' Get Stream from MailServer Dim NetworkStream As NetworkStream = TcpClient.GetStream() ' Get the Response Dim Response As String = GetData(NetworkStream) Response = TalkToServer(NetworkStream, "HELO " & RemoteAddress & vbCrLf) Response = TalkToServer(NetworkStream, "MAIL FROM: " & FromAddress & vbCrLf) If ValidResponse(Response) Then Response = TalkToServer(NetworkStream, "RCPT TO: " & ToAddress & vbCrLf) If ValidResponse(Response) Then ' Valid response from the SMTP server CheckEmailAddress = 1 Else ' Invalid response from the SMTP server CheckEmailAddress = -1 End If End If ' Close the connections TalkToServer(NetworkStream, "QUIT" & vbCrLf) TcpClient.Close() NetworkStream = Nothing Catch ' A general communication error has occured CheckEmailAddress = -2 End Try Else ' No mail server can be found CheckEmailAddress = -3 End If Else ' No domain name has been specified CheckEmailAddress = -4 End If End Function
The mail server validation is taken and adapted from http://www.15seconds.com/issue/030203.htm.