这个VB6COM组件提供了一项即时邮件查询的功能。它有效的避免了向一个不存在的账户发送邮件的情况。例如,在ASP页面里面检查用户输入的邮件地址是否正确,并避免在你的用户数据库里面存储相关的错误信息。
主要内容
工作原理
让我们首先来看一下这个组件是如何进行工作的。
首先给定一个E-mail地址(例如:someone@somewhere.com),然后它会执行如下的步骤:
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\SYSTEM32\
对于Windows 9 x:C:\WINDOWS\SYSTEM\
l 在注册表中注册组件:
在运行中输入:regsvr32 c:\winnt\system32\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 …… http://guoyang1982.blog.163.com/blog/static/61488351201048112520678/ http://wkf41068.iteye.com/blog/1596636
Java验证邮箱是否真实存在有效
要检测邮箱是否真实存在,必须了解两方面知识: 1. MX记录,winodws的nslookup命令。查看学习 2. SMTP协议,如何通过telnet发送邮件。查看学习
有个网站可以校验,http://verify-email.org/, 不过一小时只允许验证10次。
直接上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
import java.io.IOException;
import org.apache.commons.net.smtp.SMTPClient; import org.apache.commons.net.smtp.SMTPReply; import org.xbill.DNS.Lookup; import org.xbill.DNS.Record; import org.xbill.DNS.Type;
public class CheckEmailObj { public static boolean checkEmail(String email) { if (!email.matches("[\\w\\.\\-]+@([\\w\\-]+\\.)+[\\w\\-]+")) { System.err.println("Format error"); return false; }
String log = ""; String host = ""; String hostName = email.split("@")[1]; Record[] result = null; SMTPClient client = new SMTPClient();
try { // 查找MX记录 Lookup lookup = new Lookup(hostName, Type.MX); lookup.run(); if (lookup.getResult() != Lookup.SUCCESSFUL) { log += "找不到MX记录\n"; return false; } else { result = lookup.getAnswers(); }
// 连接到邮箱服务器 for (int i = 0; i < result.length; i++) { host = result[i].getAdditionalName().toString(); client.connect(host); if (!SMTPReply.isPositiveCompletion(client.getReplyCode())) { client.disconnect(); continue; } else { log += "MX record about " + hostName + " exists.\n"; log += "Connection succeeded to " + host + "\n"; break; } } log += client.getReplyString();
// HELO cyou-inc.com client.login("cyou-inc.com"); log += ">HELO cyou-inc.com\n"; log += "=" + client.getReplyString();
// MAIL FROM: <zhaojinglun@cyou-inc.com> client.setSender("zhaojinglun@cyou-inc.com"); log += ">MAIL FROM: <zhaojinglun@cyou-inc.com>\n"; log += "=" + client.getReplyString();
// RCPT TO: <$email> client.addRecipient(email); log += ">RCPT TO: <" + email + ">\n"; log += "=" + client.getReplyString();
if (250 == client.getReplyCode()) { return true; } } catch (Exception e) { e.printStackTrace(); } finally { try { client.disconnect(); } catch (IOException e) { } // 打印日志 System.err.println(log); } return false; }
public static void main(String[] args) { System.err.println("Outcome: " + CheckEmailObj.checkEmail("pandajj0703@gmail.com")); } }
|
需要的两个jar包: http://www.dnsjava.org/download/ http://apache.etoak.com /commons/net/binaries/commons-net-2.0.zip
执行结果: MX record about gmail.com exists. Connection succeeded to alt2.gmail-smtp-in.l.google.com. 220 mx.google.com ESMTP p37si6502151gvf.9 >HELO cyou-inc.com =250 mx.google.com at your service >MAIL FROM: <zhaojinglun@cyou-inc.com> =250 2.1.0 OK p37si6502151gvf.9 >RCPT TO: <pandajj0703@gmail.com> =250 2.1.5 OK p37si6502151gvf.9
Outcome: true
或者通过webservice实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
import java.io.PrintWriter; import java.net.URL; import java.net.URLConnection;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
public class CheckEmailWS { public static boolean checkEmail(String email) { String soapRequestData = "" + "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\">" + " <soap:Body>" + " <IsValidEmail xmlns=\"http://www.webservicex.net\">" + " <Email>" + email + "</Email>" + " </IsValidEmail>" + " </soap:Body>" + "</soap:Envelope>";
try { URL u = new URL( "http://www.webservicex.net/ValidateEmail.asmx?op=IsValidEmail"); URLConnection uc = u.openConnection(); uc.setDoOutput(true); uc.setRequestProperty("Content-Type", "application/soap+xml; charset=utf-8"); PrintWriter pw = new PrintWriter(uc.getOutputStream()); pw.println(soapRequestData); pw.close();
DocumentBuilderFactory bf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = bf.newDocumentBuilder(); Document document = db.parse(uc.getInputStream());
String res = document.getElementsByTagName("IsValidEmailResult") .item(0).getTextContent();
return Boolean.parseBoolean(res); } catch (Exception e) { e.printStackTrace(); return false; } }
- 1.SMTP是工作在两种情况下:一是电子邮件从客户机传输到服务器;二是从某一个服务器传输到另一个
- 服务器
- 2.SMTP是个请求/响应协议,命令和响应都是基于ASCII文本,并以CR和LF符结束。响应包括一个表示返
- 回状态的三位数字代码
- 3.SMTP在TCP协议25号端口监听连接请求
- 4.连接和发送过程
- SMTP协议说复杂也不复杂(明明带有“简单”这个词嘛),说简单如果你懂得Sock。不过现在只是我们利用的就是第一条中说的,从客户机传输到服务器,当我们向一台服务器发送邮件时,邮件服务器会首先验证邮件发送地址是否真的存在于本服务器上。
- 操作的步骤如下:
- 连接服务器的25端口(如果没有邮件服务,连了也是白连)
- 发送helo问候
- 发送mail from命令,如果返回250表示正确可以,连接本服务器,否则则表示服务器需要发送人验证。
- 发送rcpt to命令,如果返回250表示则Email存在
- 发送quit命令,退出连接
- private static String[] removeInvalidateAddress(String[] addresses, String mailFrom)
- {
- ArrayList<String> validateAddresses = new ArrayList<String>();
- String normalAddress = null;
- int code;
-
- SMTPTransport smptTrans = null;
- if(StringUtils.isEmpty(mailFrom) || null == addresses)
- {
- return new String[0];
- }
- String sendCmd = "MAIL FROM:" + normalizeAddress(mailFrom);
- try
- {
- smptTrans = (SMTPTransport)sendSession.getTransport("smtp");
- smptTrans.connect();
- code = smptTrans.simpleCommand(sendCmd);
- if(code != 250 && code != 251)
- {
- logger.error("send from invalidate" + mailFrom);
- }
- else
- {
- for(String address : addresses)
- {
- normalAddress = normalizeAddress(address);
- String cmd = "RCPT TO:" + normalAddress;
- code = smptTrans.simpleCommand(cmd);
- if(code == 250 || code == 251)
- {
- validateAddresses.add(address);
- }
- }
- }
- }
- catch(MessagingException e)
- {
- logger.error("Validate mail address error. send from " + mailFrom, e);
- }
-
- String[] result = validateAddresses.toArray(new String[validateAddresses.size()]);
- return result;
- }
-
- private static String normalizeAddress(String addr)
- {
- if ((!addr.startsWith("<")) && (!addr.endsWith(">")))
- return "<" + addr + ">";
- else
- return addr;
- }
|
|
http://blog.youkuaiyun.com/zapldy/article/details/3971579 http://blog.youkuaiyun.com/qq690197664/article/details/4453833 |