STLVisual Studio 6Visual C++ 7.0.NET 1.0Windows 2000Visual C++ 6.0Windows XPMFC中级开发Visual StudioWindowsC++.NET
获取 MX 记录(简单方法)






4.55/5 (13投票s)
2003年2月28日
3分钟阅读

141255

2076
使用 DNSQuery() 获取 MX 记录。
简介
几个月前,我正在开发一个应用程序,该应用程序会将电子邮件发送给已订阅新闻稿的用户。 我知道有很多群发邮件应用程序,但我真的想开发一个内部解决方案。 我在本文中介绍的是系统用于验证电子邮件地址的一组类。功劳归于创作者
按照我文章中的惯例,我必须感谢 James Oldroyd 帮助我找到了::DnsQuery()
函数。 James 是一位了不起的程序员,如果你能让他停止以代码思考超过五分钟,你甚至可以和他交谈。 在使用 ::DNSQuery()
之前,我检查了一些 C 代码,这些代码连接到 DNS 服务器并执行 MX 记录请求——至少可以说是一团真正的糟糕代码。 因此,找到并使用 ::DNSQuery()
函数是明智之举。概述
演示应用程序是一个 Windows 控制台应用程序,它以交互方式接受电子邮件地址。 输入电子邮件地址并按 RETURN 键开始电子邮件地址验证过程。 键入 exit 并按 RETURN 键将退出应用程序。 简单的演示使用了我将在本文中描述的两个类,CGetSMTPHostName
(它使用 ::DnsQuery()
)和 CVerifySMTPEmailAddress
(它执行实际的电子邮件验证)。 应该注意的是,我决定将这些类分成两个不同的类,因为我打算使用它们的方式,但它们可以组合成一个类。 下面我将简要描述每一个类。CGetSMTPHostName
CGetSMTPHostName 类提供了三个成员函数:GetSmtpHostName()
、ResetHostMap()
和 Dump()
。 它还包含一个 std::map
,其中保存了 DomainName 和 SMTPHostName 对。CGetSMTPHostName::GetSmtpHostName()
此方法接受一个电子邮件地址和一个 CString& 来返回电子邮件地址的主机名。 使用::DNSQuery()
函数找到主机名。 该函数首先剥离电子邮件地址的域部分,并在我们的 std::map
中查找以确定我们是否之前对该域执行过查找。 如果是,我们将返回主机名,我们就完成了。 如果不是,那么我们调用 ::DNSQuery()
来确定主机名。 如果调用成功,我们将域和主机名对插入到 std::map
并返回。 这是代码BOOL CGetSMTPHostName::GetSmtpHostName(CString _EmailAddress,
CString& _HostName) { BOOL bRV = TRUE; _HostName.Empty(); int start = _EmailAddress.Find('@')+1; CString strDomain
= _EmailAddress.Mid(start,_EmailAddress.GetLength()-start); if( ! strDomain.IsEmpty()) { // First, look in our map to see if we have looked up this SMTP
// Host before m_SMTPHostIterator = m_SMTPHost.find(strDomain); if(m_SMTPHostIterator != m_SMTPHost.end()) { // Great, we've looked this one up before... _HostName = (*m_SMTPHostIterator).second; // Is it unknown??? if(_HostName == "UNK") { bRV=FALSE; _HostName.Empty(); } } else { // OK, we haven't looked this up before, so look it up DNS_RECORD* ppQueryResultsSet = NULL; DNS_STATUS statusDNS = ::DnsQuery( strDomain, DNS_TYPE_MX, DNS_QUERY_STANDARD, NULL, &ppQueryResultsSet, NULL ); if(statusDNS == ERROR_SUCCESS) { // Found the SMTP Host Name, insert it into our map _HostName = ppQueryResultsSet->Data.MX.pNameExchange; m_SMTPHost.insert(HostMapValue(strDomain,_HostName)); } else { // I have opted to place unknown domains in the map to reduce // the time that I spend looking up the domain names. You // may want to implement this differently for your usage. bRV = FALSE; DNS_STATUS theError = statusDNS; m_SMTPHost.insert(HostMapValue(strDomain,"UNK")); } } } else { // OOPS, is this a valid email address? bRV = FALSE; } return(bRV); }
CGetSMTPHostName::ResetHostMap()
此方法只是一个实用程序函数,用于清除std::map
,以防你需要重新开始。CGetSMTPHostName::Dump()
另一个实用程序函数,用于将包含在std::map
中的域和主机名列表打印到控制台。CVerifySMTPEmailAddress
此类包含(有一个)CGetSMTPHostName
类作为私有成员,并且有一个名为 VerifyEmailAddress()
的公共方法,如下所示BOOL CVerifySMTPEmailAddress::VerifyEmailAddress(CString _EmailAddress) { CString strHostName; if(m_GetSmtpHostName.GetSmtpHostName(_EmailAddress, strHostName)) { return(Connect(strHostName, _EmailAddress)); } return(FALSE); }
main() or _tmain()
这是控制台应用程序的主要函数int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) { int nRetCode = 0; // initialize MFC and print and error on failure if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) { // TODO: change error code to suit your needs cerr << _T("Fatal Error: MFC initialization failed") << endl; nRetCode = 1; } else { CVerifySMTPEmailAddress vrfyemail; CString strSMTPAddress; CString strHostName; char caSMTPAddress[128]; while(TRUE) { std::cout << "Enter SMTP Address : "; std::cin >> caSMTPAddress; strSMTPAddress = caSMTPAddress; strSMTPAddress.MakeLower(); if(strSMTPAddress == "exit") { break; } if(vrfyemail.VerifyEmailAddress(strSMTPAddress)) { std::cout << strSMTPAddress.GetBuffer(0) << " is VALID"
<< std::endl; } else { std::cout << strSMTPAddress.GetBuffer(0) << vrfyemail.GetLastError()
<< std::endl; } strSMTPAddress.Empty(); } } return nRetCode; }
注释
::DNSQuery()[^] 可以用于比 MX 记录查找多得多的用途。 可以在 MSDN 上找到信息(单击链接)。我更喜欢使用
#pragma comment
来链接库,尤其是在像这样的演示应用程序中。 你可以设置链接库以适合你的口味。