編者按:檢測郵件地址的有效性可應用于防止垃圾郵件、用戶非法注冊等方面,本文將以編程的方式進行探討,相信能給大家一些啟示。
編程實現郵件地址有效性檢測
文/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技術!