編者按:檢測郵件地址的有效性可應用于防止垃圾郵件、用戶非法注冊等方面,本文將以編程的方式進行探討,相信能給大家一些啟示。
編程實現郵件地址有效性檢測
文/brain
這個vb6com組件提供了一項即時郵件查詢的功能。它有效的避免了向一個不存在的賬戶發送郵件的情況。例如,在asp頁面里面檢查用戶輸入的郵件地址是否正確,并避免在你的用戶數據庫里面存儲相關的錯誤信息。
主要內容
工作原理
讓我們首先來看一下這個組件是如何進行工作的。
首先給定一個e-mail地址(例如:[email protected]),然后它會執行如下的步驟:
1、 將用戶名(someone)從域名(somewhere.com)中分離出來;
2、 在dns(域名服務器)上進行查詢:域名是否可用;
3、 如果dns做出響應,它將在服務器上對mx進行查詢(mail exchanger郵件交換服務器),并試著與在這個域中每一個mx建立會話,直到建立會話成功;
4、 通過使用smtp協議,它使用vrfy命令和mail handshake(helo,mailt from,rcpt to)來驗證用戶名在該域中的存在;
5、 隨后組件將返回測試的結果,并給出四種可能的結果:
l “域”不存在。服務器做出否定響應。
l “域”存在,但是無法查詢用戶名(見注釋)。服務器做出部分確認響應。
l “域”存在,但是用戶名不存在。服務器做出否定響應。
l “域”和用戶名都存在。服務器做出完全確認響應。
注釋:
如果“域”存在,但是mx(郵件交換服務器)并不存在于該域中(典型特征是二級域名由isp掌握著),這樣通過smtp協議將會無效,應為那些服務器被指派去接受子域中的郵件,并且根本不會檢查用戶名。所以組建的程序設計,從這里跳出并返回出部分確認響應。
組件特征
l 在本地機器上查找dns。所以必須保持計算機與互聯網的連接以確保組建的正常工作
l 通過simplednsrosolover組件(見credits)發送dns請求
l 使用upd協議接收dns響應
l 經過標準的winsock.ocx接口,建立smtp會話
l 提供小型的可執行文件(編譯為一個小于50kb的activex dll 動態連接庫文件)
l 無任何用戶接口,需要activex組建支持的語言(例如,vbscript, asp, vc++等等)
l 使用vb6.0 service pack 4(已測試) 環境下編譯,當然也可以在以前的支持winsock.ocx的vb版本中編譯(例如vb5.0)
安裝方法
l 將壓縮包釋放到你選定的目錄中;
l 將vfabemailutils.dll拷貝到你的系統目錄下:
對于windows nt:c:/winnt ystem32/
對于windows 9 x:c:/windows ystem/
l 在注冊表中注冊組件:
在運行中輸入:regsvr32 c:/winnt ystem32/vfabemailutils.dll
l 重要提示:
為確保組件的正常運行,你必須安裝simple dns resolver v1.0(emmanuel kartmann’s)。相關信息,請看下面的credits。
使用方法
l 創建一個組建的應用實例
l 加入屬性:
emailaddr
smtptimeout
dns server address(僅限windows9x)
l 調用checkdomain 方法
l 測試result屬性,如果返回的結果不等于vfbinvaliddomain (1)則可以進行如下操作
l 調用checkusername 方法
l 然后測試result屬性來返回最終結果:
vfabnotverify = 0
vfabinvaliddomain = 1
vfabvaliddomain = 2
vfabvaliddomaininvalidaccount = 3
vfabvaliddomainvalidaccount = 4
示例代碼
dim ovfab
set ovfab=createobject("vfabemailutils.emailcheck") '創建對象
ovfab.emailaddr = request.form("email")
'從asp頁面獲得郵件地址以進行測試,
'并指派給該對象中的emailaddr屬性
ovfab.checkdomain '檢查域是否存在
if ovfab.result <> 1 then
'如果存在則對用戶名進行檢測
ovfab.smtptimeout = 10 '給該對象10秒鐘的時間用來連接遠程smtp服務器
ovfab.checkusername '嘗試進行smtp會話,測試用戶名
end if
…… '在這里可以用html格式顯示會話紀錄
ovfab.clear '關閉連接, 清除日志, 恢復初始狀態
組件文檔
方法(表1):
名稱
描述
checkdomain()
檢查郵件地址中的域名部分是否是有效的(存在的)域名
checkusername()
通過smtp協議檢查用戶名是否是該域中的有效郵件賬號
clear()
在結束任務之后,關閉連接, 清除日志, 恢復初始狀態
表1
屬性(表2):
名稱
類型
可讀
可寫
描述
emailaddr
string
yes
yes
指定要檢驗的郵件地址
result
integer
yes
no
從checkdomain 和(或)checkusername 方法中獲得處理結果
smtptimeout
integer
yes
yes
獲得/設置timeout(超時-秒計)等待smtp連接
dnsserver
string
yes
no
設置域名服務器的ip地址(win9x中為必選項,windows nt 中為可選項)
realname
string
yes
no
在checkusername()被執行后,如果smtp服務器提供的話,獲得用戶的真實名稱
domainname
string
yes
no
獲得emailaddr中的域名部分
username
string
yes
no
獲得emailaddr中的用戶名部分
log(blnhtml)
string
yes
no
檢索會話日志(客戶段與服務器的所有信息交換)如果可選參數被設為true,它將重新以html格式排列斷點以便閱讀。
smtpserver
string
yes
no
在域中獲得完整地郵件交換服務器列表
表2
下面將對主要代碼進行分析:
1、檢測域名有效性:
public enum emailverifiedconst '創建一個枚舉類型
…… '包含result屬性來返回最終結果
end enum
dim withevents owinsock as winsock '創建一個包含事件的winsock對象,事件dataarrival在下面被定義
……
public sub checkdomain() '聲明定義checkdomain方法
dim odns as new simplednsresolverlib.simplednsclient
'基于simplednsresolverlib建立對象odns
intpos = instr(stremailaddr, "@") '計算用戶名的長度
if intpos = 0 then '如果返回的結果是0
err.raise vbobjecterror + 699, , "請指定有效的郵件地址!"
exit sub '并從sub過程中跳出
end if
strusername = left(stremailaddr, intpos - 1) '獲得用戶名
strdomainname = mid(stremailaddr, intpos + 1) '獲得域名
……
odns.separator = ", " '設置各地址之間的分隔符為”,”
intresult = emailverifiedconst.vfabinvaliddomain '以枚舉emailverifiedconst中的成員vfabinvaliddomain賦初值給intresult
strlog = strlog & "dns -> query: mx records for " & strdomainname & vbcrlf '進行日志記錄
on error resume next '發生錯誤繼續
odns.getemailservers strdomainname, strsmtpservers '利用odns對象的getmailserver方法給strsmtpservers賦值
if err <> 0 then
err.raise vbobjecterror + 698, , err.description
end if
strlog = strlog & "dns <- " & strsmtpservers & vbcrlf '進行日志記錄
if strsmtpservers <> "" then
intresult = emailverifiedconst.vfabvaliddomain '以枚舉emailverifiedconst中的成員vfabvaliddomain賦值給intre、sult
end if
end sub
2、檢測用戶名的有效性:
public sub checkusername() '聲明定義checkusername()方法
dim strhost as string, i as integer, intoldstep as integer
i = 1 '在這里定義循環初始值,并以之為計數標志分割strsmtpservers
……
do while true '開始進行循環1
strhost = trim(ltrim(token(strsmtpservers, ",", i)))
'以”,”為分隔符分離字符串中的所有地址,使之各個獨立,
'i是計數標志,下面對token()的聲明定義中再作解釋。
if strhost = "" then '如果發現在“,”后有空地址
exit do '跳出循環
end if
if instr(strhost, strdomainname) > 0 then '如果域名以前的部分不是空
with owinsock '設置owinsock對象所使用的
.protocol = scktcpprotocol '協議為tcp
.remotehost = strhost '主機地址為strhost的值
.remoteport = 25 '通信端口為25
.connect '并進行連接
dbltimeout = intsmtptimeout '設置超時
intstep = 1 '將步驟索引intstep設為1
do while .state <> sckconnected '如果套接字狀態是非連接,開始循環2
sleep 100 '延遲100ms
doevents '執行owinsock包含事件dataarrival
'dataarrival事件是用來對接收到的
'做出反應用的;事件的定義在下面可以找到
'該事件發生之后,會影響intstep、連接狀態等
dbltimeout = dbltimeout - 0.1 '超時減0.1秒
loop
if .state <> sckconnected then '如果套接字狀態是非連接
exit sub '跳出函數體,結束對該方法的調用
end if
do while true '循環3
select case intstep '依據步驟intstep進行判斷
……
case 2
senddata "vrfy " & strusername & "@" & strdomainname & vbcrlf '發送待確認請求
case 3
.close '關閉套接字
exit do '并結束循環3
…… '在這里可以使用mail handshake 方式 相應的步驟 4、5、6
end select
intoldstep = intstep '保護現場 保存intstep當前值
dbltimeout = intsmtptimeout
'設置超時
do while intstep = intoldstep and dbltimeout > 0 '如果沒有發生連接超時 進行循環4
sleep 100 '延時100ms
doevents '執行owinsock包含事件dataarrival
dbltimeout = dbltimeout - 0.1
loop
if dbltimeout < 0 then '如果發生超時
intstep = 0 '設置intstep為0
exit do '并跳出循環3
end if
loop
if intstep = 3 then '如果intstep=3即 已套接字關閉
exit do '跳出循環1
end if
.close '關閉套接字
sleep 1000
end with
end if
i = i + 1 '對計數標志i進行自增運算,以保證可以讀到下一個地址
loop
end sub
3、分割郵件地址,用于輸入多個郵件地址時,這正是上面使用的token函數的定義
private function token(byval strinput as string, strsep as string, byval intoccur as integer) as string '聲明定義函數token
dim i as long, intlen as integer
strinput = strsep & strinput & strsep '使strinput被賦值,格式為“,strsmtpservers,”
intlen = len(strsep) '獲得字符串的長度
for i = 1 to len(strinput) '在這里取出我們需要的地址 以checkdomain中
'的i為參數,這里的i為循環標志
if mid(strinput, i, intlen) = strsep then intoccur = intoccur – i '如果第i位取得的字符正好是分隔符,則以i與intoccur比較
if intoccur = 0 then '如果這里取得的地址也在第i位(checkdomain中,即intoccur)
token = mid(strinput, i + 1) '則可以在這里取得一個獨立的郵件地址
if len(token) > 0 then
i = instr(token, strsep)
if i > 1 then
token = left(token, i - 1)
end if
end if
exit for
end if
next i
end function
例如,strsmtpservers中的字符串為 [email protected],[email protected],[email protected] 則由strinput = strsep & strinput & strsep處理過 就變為:
,[email protected],[email protected],[email protected],
再求得字符串的長度57,由1到57進行for循環。在循環中檢索,如果發現第i位就是“,”則要求checkdomain中的i(intoccur計數標志)減1,如果發現“,”所在那位數正是checkdomain中的i。例如,“,”在第15位,checkdomain中的i剛好也是15,將在strsmtpservers中取得字符串
[email protected],[email protected],
放在token中,token不為空,則在token中尋找第一個“,”并取得前面的內容重新賦給token。即
[email protected]
總結:
這個應用組件在很大程度上依賴由emmanuel kartmann 編寫的simple dns resolver。請到他的主頁上去查找更多關于dns構建和該組件的的細節。
這個組件的作用是在web頁面上用來對郵件地址的有效性進行檢測。當然主要是應用于asp,可能asp對對象的支持優于其他,易于編寫,而且vbscript能在其間發揮更出色的作用。在對使用socket方面進行連接也用比較傳統的方法,具有一定的代表性。
網站運營seo文章大全提供全面的站長運營經驗及seo技術!