Email, FTP etc.: Checking for valid email address
2003-08-12 -- Jim Kane
Newsgroups: TopSpeed.Topic.Third_Party
This is what I use. I just wrote it not long ago so if anyone who uses it
has comments please send them.
I decide to use these two test and then set up a bounce box where all emails
sent out that bounce come back to a special email address. Anything comming
back to that address needs to be investigated. I usually set up an outlook
client and use ole to control outlook to find all the bounces and strip bad
emails.
jim kane
"Geoff Bomford" wrote in message
news:3f38caeb$1@news.softvelocity.com...
> Is anyone aware of a Clarion tool that can check the MX Record of an Email
> address for a valid entry?
>
> It is the sort of thing that I would expect Nettalk to be capable of - is
> it? If so, anyone care to share some code?
Editors Note: Jim attached two files with his message, dnscl.inc and dnscl.clw.
These contain an ABC compliant class and should be placed in the Clarion LibSrc
directory:
dnscl.inc:
!ABCIncludeFile
OMIT('_EndOfInclude_',_dnsclPresent_)
_dnsclPresent_ EQUATE(1)
!Other Classes
! Include('OtherClass.INC')
!Equates - will be seen by using program
dnsclType
Class,type,module('dnscl.CLW'),LINK('dnscl.CLW',_ABCLinkMode_),DLL(_ABCDllMode_)
!Member Data
!dnsresult values:
! -1 : dns not tried - email syntax error
! 0 : dns tried and no error
! -2 : dns tried, no error reading records but no MX records were returned - domain does
not support email
!Anything else: win32 error 9000 -10000 are dns specific errors
!Methods - all return 0 for success if they return anything
SyntaxCheck Procedure(string pEmail,*string pErrorStr, *cstring
domain),byte,private
ValidateEmailAddr Procedure(string pEMailAddr, *String pErrorstr, *long
DnsResult),byte
FormatErrMsg Procedure(*string errmsg,long EC),private
end
!_EndOfInclude_
dnscl.clw:
Member
_ABCDllMode_ EQUATE(0)
_ABCLinkMode_ EQUATE(1)
Map
!Local Procedures, if any, go here
!API Prototypes
Module('api')
DnsQuery(*cstring pDomainName, ushort pWType=15, long fOptions=0, |
long plpServerList=0, *long plpResult, long Reserved=0),|
long,pascal,proc,raw,name('DnsQuery_A')
DnsRecordListFree(long plpResult, long pfreeType=1),pascal,raw,proc
getlasterror(),long,pascal
memcpy(long,long,signed),long,proc,name('_Memcpy')
lstrlen(long),SIGNED,PASCAL,NAME('lstrLenA')
FormatMessage(ulong,long,ulong,ulong,long,ulong,long),ulong,PASCAL,RAW,Name('FormatMessageA')
LocalFree(long),long,PASCAL,proc
End
end
!Includes this class and others
include('dnscl.inc')
!global data for this module
Return:Benign equate(0)
Return:Fatal equate(3)
Return:Notify equate(5)
maxemaillength equate(100)
!-------------------------------------------------------------
!---Start of dnscltype
!-------------------------------------------------------------
dnscltype.SyntaxCheck procedure(string pEmail,*string pErrorStr,
*cstring pdomain)
!purpose: do a syntax check on the email address
!input: email address,
!output: place to write an error description and the domain portion
!return value: beign-good email; Notify - bad email; Fatal - error - cant tell
AtCharIdx long,auto
L long,auto
Mailbox string(maxemaillength)
DomainPrefix string(maxemaillength)
DomainSuffix string(maxemaillength)
LastPeriodIdx long
thechar string(1)
I long
partlen long
!Match:Simple EQUATE(0)
!Match:Wild EQUATE(1)
!Match:Regular EQUATE(2)
!Match:Soundex EQUATE(3)
!Match:NoCase EQUATE(10H) ! May be added to Simple,Wild and Regular
code
L=len(clip(pEmail))
if L >MaxEmailLength then
pErrorStr='Email address too long!'
return return:notify
end
if L<3 then
pErrorstr='Email address too short.'
return return:notify
end
if pemail[1]='<<' or pEmail[L]='>' then
pErrorstr='Angle brackets arround the address must be removed.'
return return:notify
end
!find the 1st @ char
AtCharIdx=instring('@',pemail,1,1)
if ~AtCharidx or AtCharidx>=L then
pErrorstr='@ character is not in a legal place.'
return return:notify
end
Mailbox=pEmail[1 : atCharIdx-1]
pdomain=pEmail[atCharIdx + 1 : L]
!Message('email parts: ' & clip(mailbox) & ' ' & clip(DomainPrefix) & ' ' &
clip(DomainSuffix))
!see http://www.netusi.com/regExp.htm
!not going to support the @[10.1.23.1] format which is legal for the
domainprefix&'.'&domainsuffix
!format for the mail box name
! ^([A-Za-z0-9_]\-\.]+)
partlen=len(clip(mailbox))
loop I= 1 to partlen
thechar=upper(mailbox[i])
if (thechar>='A' and theChar<='Z') or |
(thechar>='0' and theChar<='9') or |
thechar='_' or |
theChar='-' or |
thechar='.' then
cycle !good char
else
pErrorstr='The mail box name may only contain letters, numbers, dash, underline and
periods.'
Return return:notify
end
end
!find the last period in the email - must be before the @ sign
LastPeriodIdx=0
loop I= L to AtCharIdx+1 by -1
if pEmail[I]='.' then
LastPeriodidx=I
break
end
end
if ~LastPeriodIdx or L - LastPeriodIdx < 2 or L - LastPeriodIdx>4 then
pErrorstr='There must be 2 to 4 characters after the final period at the end of the
email.'
return return:notify
end
!break the domain into 2 parts
DomainPrefix=pEmail[atCharIdx+1 : LastPeriodIDx-1]
DomainSuffix=pEmail[LastPeriodIdx+1 : L]
!look for the [nn.nn.nn.n]
partlen=len(clip(pDomain))
if pDomain[1]='[' and pDomain[PartLen]=']' then
!special [nn.nn.nn.n] syntax
if pDomain[2]='.' or pdomain[PartLen-1]='.' or PartLen<9 or PartLen>17 then
pErrorstr='To use an ip address for the domain the syntax is [nnn.nnn.nnn.nnn].'
return return:notify
end
Loop I=1 to partlen
thechar=pdomain[I]
if thechar='.' or (thechar>='0' and thechar<='9') then
!good char
cycle
end
pErrorstr='To use an ip address for the domain the syntax is [nnn.nnn.nnn.nnn].'
return return:notify
end
Return return:benign !no further domain check is needed
end
!format for the DomainPrefix
! (([[A-Za-z0-9_]\-]+\.)+)
L=len(clip(DomainPrefix))
loop I=1 to L
thechar=upper(domainPrefix[i])
if (thechar>='A' and theChar<='Z') or |
(thechar>='0' and theChar<='9') or |
thechar='_' or |
theChar='-' or |
thechar='.' then
cycle !good char
else
pErrorstr='The domain name before the period may only contain letters, ' &|
'numbers, dash, underline and periods.'
Return return:notify
end
end
!format for the DomainSuffix
! ([a-zA-Z]{2,4})
L=len(clip(DomainSuffix))
loop I=1 to L
thechar=upper(domainSuffix[i])
if (thechar>='A' and theChar<='Z') then
cycle !good char
else
pErrorstr='The domain name after the final period may only contain letters.'
Return return:notify
end
end
return return:benign
dnsclType.ValidateEmailAddr Procedure(string pEMailAddr, *String
pErrorstr, *long DnsResult)
DomainName cstring(maxemaillength)
!DnsResult long(-1) !return value from dnsQuery. 0=no error
lpResult long !pointer to the array of dns_recordMX's
lpRecord long !pointer to the current record being read
recordcount long !counts the number of records read
MXRecordCount long !the number of mx records read (mx = mail records)
cstringRef &cstring !cstring reference variable to make displaying the cstrings
easier
dns_RecordMXType group,Type
lpNextRecord long
lpName long
wType ushort
wDataLength ushort
flags long !section:2,delete:1,charset:2,unused:3,Reserved:24
dwTtl long
dwReserved long
lpNameExchange long
wPreference ushort
pad Ushort
end
dns_RecordMx &Dns_RecordMXType
DNS_Type_MX equate(15)
res byte(return:fatal)
code
!initialize output
clear(pErrorStr)
dnsresult=-1 !not attempted
res=SELF.SyntaxCheck(pEmailAddr,pErrorStr, domainname)
if res=return:notify then
pErrorstr=clip(pErrorstr) & ' Bad email address syntax!'
end
if res then
return res
end
clear(lpResult)
clear(RecordCount)
Clear(MXRecordCount)
dnsResult = DnsQuery(domainname,DNS_Type_MX,0,0,lpResult,0)
!9002 dns server failure - tried to resolve myown domain name
!9003 means no match - name is bad
!9502 no records found for the query
!9503 means match on name but no mail server
!Message('dnsResult='&dnsresult & ' lpResult='&lpResult)
!init lpRecord to the address of the 1st record
lpRecord=lpResult
if dnsResult=0 then
loop
dns_RecordMX&=(lpResult)
if dns_recordmx.wtype=15 then
MXRecordCount+=1
!cstringRef&=(dns_RecordMX.lpName)
!Message('Name='& cstringRef)
!cstringRef&=(dns_RecordMX.lpNameExchange)
!message('Mail server='&cStringRef)
!message('timetolive='&dns_recordmx.dwttl)
!message('preference='&dns_recordmx.wPreference)
!message('DataLength='&dns_Recordmx.wDataLength)
!else
! message('wtype='&dns_recordmx.wtype)
end
recordcount+=1
if ~dns_RecordMX.lpNextRecord or dns_RecordMX.lpNextRecord=lpRecord then
!Message('done with records count='&Recordcount)
break
else
!Message('thisrec='&lprecord & ' NextRecord='&dns_RecordMX.lpNextRecord)
lpRecord=dns_RecordMX.lpNextRecord
end
end
if ~MXRecordCount then .
else
!make a message string
SeLF.formatErrMsg(pErrorStr,DnsResult)
!Message(clip(errorstr),'DNS Error')
end
!free list if any
if lpResult then
DnsRecordListFree(lpResult)
end
!show success or failure
if DNSResult=0 then
if MxRecordCount>0 then
pErrorStr='Email address is okay!'
res=return:benign !every thing good
else
!mxrecordcount<=0 and dnsresult=0
dnsresult=-2 !code for tried dns but no mx records
pErrorstr='The domain exists but does not support email.'
res=return:notify
end
elsif DNSResult=9852 or DNSResult<9000 or dnsresult>10000 then
!9852 = no network or no dns server
res=return:Fatal !wierd error like out of memory or somthing
pErrorstr='Error determining if the domain is valid. ' & clip(pErrorstr)
else
!9xxx errorcode in dns land
Res=Return:Notify !probably not a good domain
pErrorstr='Email domain bad! '& clip(pErrorstr)
end
return res
dnsclType.FormatErrMsg procedure(*string errmsg,long EC)
lpMsgBuf long,auto !Address of message string formated by FormatMessage Call
lenMsgBuf long,auto !char in cstring return by formatMessage
res byte(3)
code
If FormatMessage(1100H, | !Format_Message_Allocate_Buffer + Format_message_From_System
0, EC,0,Address(lpMsgBuf),0,0)
lenMsgBuf = lstrlen(lpmsgBuf)
If lenMsgBuf then
lenMsgBuf = choose(lenMsgBuf>size(errMsg), size(errMsg), lenmsgbuf)
Clear(errMsg)
memcpy(Address(errMsg), lpMsgBuf, lenMsgBuf)
res=0
end
If lpMsgBuf then LocalFree(lpMsgBuf). !clean up allocated memory
end
if res then errmsg='Unknown error - '&ec .
Return
Printed November 23, 2024, 3:38 am This article has been viewed/printed 35393 times.
Google search
has resulted in 546 hits on this article since January 25, 2004.
|