VB.NET驗證郵件地址的合法性實現(xiàn)代碼
更新時間:2011年04月21日 14:53:33 作者:
現(xiàn)在,對于用戶在Web頁面上或電話中給出的Email地址,我們越來越不敢肯定它是否真的有效。在今天這個垃圾郵件泛濫成災(zāi)的年代,人們完全有理由舍不得輕易透露Email地址。
一、提出問題
現(xiàn)在,對于用戶在Web頁面上或電話中給出的Email地址,我們越來越不敢肯定它是否真的有效。在今天這個垃圾郵件泛濫成災(zāi)的年代,人們完全有理由舍不得輕易透露Email地址。
另一方面,對于通過正規(guī)途徑得到的郵件地址,當我們將它用于合法的目的時,也常常要為郵件地址是否有效而煩惱,用戶可能有意或無意地寫錯地址,也可能由于長時間不訪問而導(dǎo)致郵箱失效。對于少量的郵件地址,也許可以手工驗證其合法性,例如發(fā)送測試email;但是,當郵件地址的數(shù)量達到數(shù)萬甚至更多時,手工驗證就不可能了,必須用專門的工具或自己編寫程序自動執(zhí)行驗證。
常規(guī)的驗證方法只從email地址的格式判斷其合法性,例如檢查它是否包含“@”和“.”符號。顯然,這種檢查是不充分的,郵件地址格式正確并不證明它一定有效。由于這個原因,一些網(wǎng)站采取了用email發(fā)送密碼、特殊資源的URL等辦法,或者要求用戶回復(fù)email,以此確保email地址的有效性。但是,這些辦法不見得任何時候都有效,例如,你可能不是從自己的網(wǎng)站上收集用戶email,而是通過第三者獲得。
考慮到這些原因,驗證email地址合法性最根本的辦法是查詢郵件服務(wù)器。本文將給出完成這一任務(wù)的完整VB.NET代碼。
二、郵件服務(wù)器之合法性
對于任何郵件地址,判斷其合法性的第一步當然是看看它的格式是否正確,例如是否包含“@”和“.”符號,這方面的資料很多,甚至還有現(xiàn)成的控件,所以本文不再贅述。我們的任務(wù)從判斷郵件地址的域是否合法開始,例如對于abc@sina.com.cn這個地址,首先判斷sina.com.cn的郵件服務(wù)器是否有效。
每一個域有一個MX記錄,即郵件交換器(Mail Exchanger)記錄,它指向該域內(nèi)處理email的服務(wù)器,我們只要查詢DNS服務(wù)器即可獲得該信息。Windows本身帶來的nslookup命令非常適合于完成該任務(wù),例如,要查找sina.com.cn的郵件服務(wù)器,只需執(zhí)行nslookup -type=mx sina.com.cn,其中-type=MX表示要查找MX記錄,輸出結(jié)果如圖一所示。Windows的nslookup命令要安裝了TCP/IP協(xié)議后才可用,詳細說明可參見Windows幫助。

下面的GetMailServer函數(shù)封裝了調(diào)用Windows nslookup命令的操作,根據(jù)參數(shù)中指定的域名返回郵件服務(wù)器。
Private Function GetMailServer(ByVal sDomain As String) As String
Dim info As New ProcessStartInfo()
Dim ns As Process
'調(diào)用Windows的nslookup命令,查找郵件服務(wù)器
info.UseShellExecute = False
info.RedirectStandardInput = True
info.RedirectStandardOutput = True
info.FileName = "nslookup"
info.CreateNoWindow = True
'查找類型為MX。關(guān)于nslookup的詳細說明,請參見
'Windows幫助
info.Arguments = "-type=MX " + sDomain.ToUpper.Trim
'啟動一個進行執(zhí)行Windows的nslookup命令()
ns = Process.Start(info)
Dim sout As StreamReader
sout = ns.StandardOutput
' 利用正則表達式找出nslookup命令輸出結(jié)果中的郵件服務(wù)器信息
Dim reg As Regex = New Regex("mail exchanger = (?[^\\\s]+)")
Dim mailserver As String
Dim response As String = ""
Do While (sout.Peek() > -1)
response = sout.ReadLine()
Dim amatch As Match = reg.Match(response)
If (amatch.Success) Then
mailserver = amatch.Groups("server").Value
Exit Do
End If
Loop
Return mailserver
End Function
三、郵件地址之合法性
只要郵件地址中指定的域合法,我們就可以連接郵件服務(wù)器,試著發(fā)送一個email。如果郵件服務(wù)器回答說該用戶非法或不存在,表明郵件地址無效。這一步的主要操作包括創(chuàng)建一個連接郵件服務(wù)器的Socket,然后按照SMTP郵件傳輸協(xié)議的要求與服務(wù)器通信,完成郵件發(fā)送操作。關(guān)于SMTP協(xié)議的詳細說明,有興趣的讀者可參見SMTP規(guī)范(RFC 821):http://www.ietf.org/rfc/rfc821.txt。
下面CheckEmail函數(shù)的輸入?yún)?shù)是一個郵件地址,函數(shù)的返回值表示該地址是否合法。該函數(shù)有兩個數(shù)值可隨意調(diào)整:在發(fā)送郵件的過程中,我們要向?qū)Ψ降泥]件服務(wù)器提供一個合法的域名以表明自己的身份,這里選擇的是sina.com.cn;根據(jù)網(wǎng)絡(luò)和對方郵件服務(wù)器的忙閑程度,響應(yīng)時間也會發(fā)生變化,這里選擇的等待時間是3秒。當網(wǎng)絡(luò)或?qū)Ψ椒?wù)器非常忙時,減小等待時間會增加測試失敗的可能性。
Public Function CheckEmail(ByVal sEmail As String) As Long
Dim oStream As NetworkStream
Dim sFrom As String '發(fā)件人
Dim sTo As String '收件人
Dim sResponse As String '郵件服務(wù)器的應(yīng)答
Dim Remote_Addr As String '發(fā)件人的域名
Dim mserver As String '郵件服務(wù)器
Dim sText As String()
sTo = "<" + sEmail + ">"
' 從郵件地址分離出帳戶名和域名
sText = sEmail.Split(CType("@", Char))
' 查找該域的郵件服務(wù)器
mserver = GetMailServer(sText(1))
'mserver為空值表明查找郵件服務(wù)器失敗
If mserver = "" Then
Return 4
Exit Function
End If
'發(fā)件人地址的域名必須合法
Remote_Addr = "sina.com.cn"
sFrom = " '盡可能延遲創(chuàng)建對象的時間
Dim oConnection As New TcpClient()
Try
'超時時間
oConnection.SendTimeout = 3000
'連接SMTP端口
oConnection.Connect(mserver, 25)
'收集郵件服務(wù)器的應(yīng)答信息
oStream = oConnection.GetStream()
sResponse = GetData(oStream)
sResponse = SendData(oStream, "HELO " & Remote_Addr & vbCrLf)
sResponse = SendData(oStream, "MAIL FROM: " & sFrom & vbCrLf)
'如果對MAIL FROM指令有肯定的應(yīng)答,
'至少表明郵件地址的域名正確
If ValidResponse(sResponse) Then
sResponse = SendData(oStream, "RCPT TO: " & sTo & vbCrLf)
'如果對RCPT TO指令有肯定的應(yīng)答
'表明郵件服務(wù)器已認可該地址
If ValidResponse(sResponse) Then
Return 1 '郵件地址有效
Else
Return 2 '只有域名有效
End If
End If
'結(jié)束與郵件服務(wù)器的會話
SendData(oStream, "QUIT" & vbCrLf)
oConnection.Close()
oStream = Nothing
Catch
Return 3 '錯誤!
End Try
End Function
'獲取服務(wù)器應(yīng)答數(shù)據(jù),并將其轉(zhuǎn)換為String
Private Function GetData(ByRef oStream As NetworkStream) As String
Dim bResponse(1024) As Byte
Dim sResponse As String
Dim lenStream As Integer = oStream.Read(bResponse, 0, 1024)
If lenStream > 0 Then
sResponse = Encoding.ASCII.GetString(bResponse, 0, 1024)
End If
Return sResponse
End Function
'向郵件服務(wù)器發(fā)送數(shù)據(jù)
Private Function SendData(ByRef oStream As NetworkStream, ByVal sToSend As String) As String
Dim sResponse As String
'將String轉(zhuǎn)換成Byte數(shù)組
Dim bArray() As Byte = Encoding.ASCII.GetBytes(sToSend.ToCharArray)
'發(fā)送數(shù)據(jù)
oStream.Write(bArray, 0, bArray.Length())
sResponse = GetData(oStream)
'返回應(yīng)答
Return sResponse
End Function
'服務(wù)器是否返回肯定的回答?
Private Function ValidResponse(ByVal sResult As String) As Boolean
Dim bResult As Boolean
Dim iFirst As Integer
If sResult.Length > 1 Then
iFirst = CType(sResult.Substring(0, 1), Integer)
'如果服務(wù)器返回應(yīng)答的第一個字符小于'3'
'我們認為服務(wù)器已認可剛才的操作
If iFirst < 3 Then bResult = True
End If
Return bResult
End Function
CheckEmail函數(shù)的返回值表示測試結(jié)果:1表示郵件地址合法,2表示只有域名正確(可能是用戶的郵件帳戶無效),3表示出現(xiàn)了錯誤,4表示無法找到郵件服務(wù)器。
四、用戶界面
以上我們完成了測試郵件地址是否合法的核心功能,這些函數(shù)可用于各種形式的應(yīng)用程序,包括Web服務(wù)、Windows應(yīng)用程序、控件等,最多只要修改一下聲明方式。為便于測試這些函數(shù),下面我們要做一個Windows應(yīng)用形式的簡單用戶界面。
啟動VS.NET,選擇新建Visual Basic項目、Windows應(yīng)用程序,如圖二,輸入項目名稱CheckMail以及保存位置,點擊“確定”按鈕,VS.NET創(chuàng)建一個新的項目。

從工具箱把一個文本標簽、一個輸入框和一個按鈕拖到VS.NET自動創(chuàng)建的窗體上。將窗體的TEXT屬性改為“Email地址測試”,文本標簽的TEXT屬性改為“郵件地址”,按鈕的TEXT屬性改為“Check!”,調(diào)整各個控件的位置,使其看起來整齊美觀,如圖三。

雙擊按鈕,輸入點擊按鈕時執(zhí)行的Button1_Cli
現(xiàn)在,對于用戶在Web頁面上或電話中給出的Email地址,我們越來越不敢肯定它是否真的有效。在今天這個垃圾郵件泛濫成災(zāi)的年代,人們完全有理由舍不得輕易透露Email地址。
另一方面,對于通過正規(guī)途徑得到的郵件地址,當我們將它用于合法的目的時,也常常要為郵件地址是否有效而煩惱,用戶可能有意或無意地寫錯地址,也可能由于長時間不訪問而導(dǎo)致郵箱失效。對于少量的郵件地址,也許可以手工驗證其合法性,例如發(fā)送測試email;但是,當郵件地址的數(shù)量達到數(shù)萬甚至更多時,手工驗證就不可能了,必須用專門的工具或自己編寫程序自動執(zhí)行驗證。
常規(guī)的驗證方法只從email地址的格式判斷其合法性,例如檢查它是否包含“@”和“.”符號。顯然,這種檢查是不充分的,郵件地址格式正確并不證明它一定有效。由于這個原因,一些網(wǎng)站采取了用email發(fā)送密碼、特殊資源的URL等辦法,或者要求用戶回復(fù)email,以此確保email地址的有效性。但是,這些辦法不見得任何時候都有效,例如,你可能不是從自己的網(wǎng)站上收集用戶email,而是通過第三者獲得。
考慮到這些原因,驗證email地址合法性最根本的辦法是查詢郵件服務(wù)器。本文將給出完成這一任務(wù)的完整VB.NET代碼。
二、郵件服務(wù)器之合法性
對于任何郵件地址,判斷其合法性的第一步當然是看看它的格式是否正確,例如是否包含“@”和“.”符號,這方面的資料很多,甚至還有現(xiàn)成的控件,所以本文不再贅述。我們的任務(wù)從判斷郵件地址的域是否合法開始,例如對于abc@sina.com.cn這個地址,首先判斷sina.com.cn的郵件服務(wù)器是否有效。
每一個域有一個MX記錄,即郵件交換器(Mail Exchanger)記錄,它指向該域內(nèi)處理email的服務(wù)器,我們只要查詢DNS服務(wù)器即可獲得該信息。Windows本身帶來的nslookup命令非常適合于完成該任務(wù),例如,要查找sina.com.cn的郵件服務(wù)器,只需執(zhí)行nslookup -type=mx sina.com.cn,其中-type=MX表示要查找MX記錄,輸出結(jié)果如圖一所示。Windows的nslookup命令要安裝了TCP/IP協(xié)議后才可用,詳細說明可參見Windows幫助。

下面的GetMailServer函數(shù)封裝了調(diào)用Windows nslookup命令的操作,根據(jù)參數(shù)中指定的域名返回郵件服務(wù)器。
Private Function GetMailServer(ByVal sDomain As String) As String
Dim info As New ProcessStartInfo()
Dim ns As Process
'調(diào)用Windows的nslookup命令,查找郵件服務(wù)器
info.UseShellExecute = False
info.RedirectStandardInput = True
info.RedirectStandardOutput = True
info.FileName = "nslookup"
info.CreateNoWindow = True
'查找類型為MX。關(guān)于nslookup的詳細說明,請參見
'Windows幫助
info.Arguments = "-type=MX " + sDomain.ToUpper.Trim
'啟動一個進行執(zhí)行Windows的nslookup命令()
ns = Process.Start(info)
Dim sout As StreamReader
sout = ns.StandardOutput
' 利用正則表達式找出nslookup命令輸出結(jié)果中的郵件服務(wù)器信息
Dim reg As Regex = New Regex("mail exchanger = (?
Dim mailserver As String
Dim response As String = ""
Do While (sout.Peek() > -1)
response = sout.ReadLine()
Dim amatch As Match = reg.Match(response)
If (amatch.Success) Then
mailserver = amatch.Groups("server").Value
Exit Do
End If
Loop
Return mailserver
End Function
三、郵件地址之合法性
只要郵件地址中指定的域合法,我們就可以連接郵件服務(wù)器,試著發(fā)送一個email。如果郵件服務(wù)器回答說該用戶非法或不存在,表明郵件地址無效。這一步的主要操作包括創(chuàng)建一個連接郵件服務(wù)器的Socket,然后按照SMTP郵件傳輸協(xié)議的要求與服務(wù)器通信,完成郵件發(fā)送操作。關(guān)于SMTP協(xié)議的詳細說明,有興趣的讀者可參見SMTP規(guī)范(RFC 821):http://www.ietf.org/rfc/rfc821.txt。
下面CheckEmail函數(shù)的輸入?yún)?shù)是一個郵件地址,函數(shù)的返回值表示該地址是否合法。該函數(shù)有兩個數(shù)值可隨意調(diào)整:在發(fā)送郵件的過程中,我們要向?qū)Ψ降泥]件服務(wù)器提供一個合法的域名以表明自己的身份,這里選擇的是sina.com.cn;根據(jù)網(wǎng)絡(luò)和對方郵件服務(wù)器的忙閑程度,響應(yīng)時間也會發(fā)生變化,這里選擇的等待時間是3秒。當網(wǎng)絡(luò)或?qū)Ψ椒?wù)器非常忙時,減小等待時間會增加測試失敗的可能性。
Public Function CheckEmail(ByVal sEmail As String) As Long
Dim oStream As NetworkStream
Dim sFrom As String '發(fā)件人
Dim sTo As String '收件人
Dim sResponse As String '郵件服務(wù)器的應(yīng)答
Dim Remote_Addr As String '發(fā)件人的域名
Dim mserver As String '郵件服務(wù)器
Dim sText As String()
sTo = "<" + sEmail + ">"
' 從郵件地址分離出帳戶名和域名
sText = sEmail.Split(CType("@", Char))
' 查找該域的郵件服務(wù)器
mserver = GetMailServer(sText(1))
'mserver為空值表明查找郵件服務(wù)器失敗
If mserver = "" Then
Return 4
Exit Function
End If
'發(fā)件人地址的域名必須合法
Remote_Addr = "sina.com.cn"
sFrom = "
Dim oConnection As New TcpClient()
Try
'超時時間
oConnection.SendTimeout = 3000
'連接SMTP端口
oConnection.Connect(mserver, 25)
'收集郵件服務(wù)器的應(yīng)答信息
oStream = oConnection.GetStream()
sResponse = GetData(oStream)
sResponse = SendData(oStream, "HELO " & Remote_Addr & vbCrLf)
sResponse = SendData(oStream, "MAIL FROM: " & sFrom & vbCrLf)
'如果對MAIL FROM指令有肯定的應(yīng)答,
'至少表明郵件地址的域名正確
If ValidResponse(sResponse) Then
sResponse = SendData(oStream, "RCPT TO: " & sTo & vbCrLf)
'如果對RCPT TO指令有肯定的應(yīng)答
'表明郵件服務(wù)器已認可該地址
If ValidResponse(sResponse) Then
Return 1 '郵件地址有效
Else
Return 2 '只有域名有效
End If
End If
'結(jié)束與郵件服務(wù)器的會話
SendData(oStream, "QUIT" & vbCrLf)
oConnection.Close()
oStream = Nothing
Catch
Return 3 '錯誤!
End Try
End Function
'獲取服務(wù)器應(yīng)答數(shù)據(jù),并將其轉(zhuǎn)換為String
Private Function GetData(ByRef oStream As NetworkStream) As String
Dim bResponse(1024) As Byte
Dim sResponse As String
Dim lenStream As Integer = oStream.Read(bResponse, 0, 1024)
If lenStream > 0 Then
sResponse = Encoding.ASCII.GetString(bResponse, 0, 1024)
End If
Return sResponse
End Function
'向郵件服務(wù)器發(fā)送數(shù)據(jù)
Private Function SendData(ByRef oStream As NetworkStream, ByVal sToSend As String) As String
Dim sResponse As String
'將String轉(zhuǎn)換成Byte數(shù)組
Dim bArray() As Byte = Encoding.ASCII.GetBytes(sToSend.ToCharArray)
'發(fā)送數(shù)據(jù)
oStream.Write(bArray, 0, bArray.Length())
sResponse = GetData(oStream)
'返回應(yīng)答
Return sResponse
End Function
'服務(wù)器是否返回肯定的回答?
Private Function ValidResponse(ByVal sResult As String) As Boolean
Dim bResult As Boolean
Dim iFirst As Integer
If sResult.Length > 1 Then
iFirst = CType(sResult.Substring(0, 1), Integer)
'如果服務(wù)器返回應(yīng)答的第一個字符小于'3'
'我們認為服務(wù)器已認可剛才的操作
If iFirst < 3 Then bResult = True
End If
Return bResult
End Function
CheckEmail函數(shù)的返回值表示測試結(jié)果:1表示郵件地址合法,2表示只有域名正確(可能是用戶的郵件帳戶無效),3表示出現(xiàn)了錯誤,4表示無法找到郵件服務(wù)器。
四、用戶界面
以上我們完成了測試郵件地址是否合法的核心功能,這些函數(shù)可用于各種形式的應(yīng)用程序,包括Web服務(wù)、Windows應(yīng)用程序、控件等,最多只要修改一下聲明方式。為便于測試這些函數(shù),下面我們要做一個Windows應(yīng)用形式的簡單用戶界面。
啟動VS.NET,選擇新建Visual Basic項目、Windows應(yīng)用程序,如圖二,輸入項目名稱CheckMail以及保存位置,點擊“確定”按鈕,VS.NET創(chuàng)建一個新的項目。

從工具箱把一個文本標簽、一個輸入框和一個按鈕拖到VS.NET自動創(chuàng)建的窗體上。將窗體的TEXT屬性改為“Email地址測試”,文本標簽的TEXT屬性改為“郵件地址”,按鈕的TEXT屬性改為“Check!”,調(diào)整各個控件的位置,使其看起來整齊美觀,如圖三。

雙擊按鈕,輸入點擊按鈕時執(zhí)行的Button1_Cli
相關(guān)文章
NetCore實現(xiàn)全局模型綁定異常信息統(tǒng)一處理(場景分析)
本文主要講解NetCore如何使用中間件捕獲模型綁定的異常信息,對NetCore實現(xiàn)全局模型綁定異常信息統(tǒng)一處理場景分析及實現(xiàn)代碼感興趣的朋友一起看看吧2021-12-12dz asp.net論壇中函數(shù)--根據(jù)Url獲得源文件內(nèi)容
從asp.net dz論壇發(fā)現(xiàn)的這個函數(shù),學(xué)習(xí)一下高手的經(jīng)驗代碼2008-09-09Asp.Net模擬表單提交數(shù)據(jù)和上傳文件的實現(xiàn)代碼
這篇文章主要介紹了Asp.Net模擬表單提交數(shù)據(jù)和上傳文件的實現(xiàn)代碼,本文對3種情況都做了介紹,只有普通數(shù)據(jù)的表單、只上傳文件的表單、包含普通數(shù)據(jù)和上傳文件表單,需要的朋友可以參考下2014-08-08asp.net中調(diào)用Office來制作3D統(tǒng)計圖的實例代碼
這篇文章介紹了asp.net中調(diào)用Office來制作3D統(tǒng)計圖的實例代碼,有需要的朋友可以參考一下2013-11-11理解ASP.NET Core 依賴注入(Dependency Injection)
把有依賴關(guān)系的類放到容器中,解析出這些類的實例,就是依賴注入。目的是實現(xiàn)類的解耦。本文主要介紹了ASP.NET Core 依賴注入(Dependency Injection),需要了解具體內(nèi)容的可以仔細閱讀這篇文章,希望對你有所幫助2021-09-09C#(.NET)數(shù)據(jù)訪問連接、查詢、插入等操作的封裝類
一個C#(.NET)數(shù)據(jù)訪問連接、查詢、插入等操作的封裝類2008-05-05