How to validate an email address in .NET

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.

Leave a Reply

Your email address will not be published. Required fields are marked *