Click here to Skip to main content
Click here to Skip to main content

Getting an MX record (the easy way)

, 27 Feb 2003
Rate this:
Please Sign up or sign in to vote.
Using DNSQuery() to get an MX record
<!-- Add the rest of your HTML here -->

Introductuion

A few months ago I was working on an application that would send emails to users that had subscribed to a newsletter. I know that there are numerous mass mail applications but I really wanted to develop an in-house solution. What I present in this article is a set of classes that are used by the system to validate email addresses.

Credit where it's due

As has come to be my modus operandi in my articles, I have to give thanks to James Oldroyd for helping me find the ::DnsQuery() function. James is an amazing coder and if you can get him to stop thinking in code for more than five minutes you can even have a conversation with him. Before using ::DNSQuery() I had examined some C code that connected to the DNS server and did an MX record request – a real nasty mess of code to say the least. So finding and then using the ::DNSQuery() function was a no-brainer.

Overview

The demo application is a Windows Console Application that accepts email addresses interactively. Entering an email address and pressing the RETURN key starts the email address validation process. Typing exit and pressing the RETURN key will exit the application. The simple demo makes use of two classes that I am describing in this article, CGetSMTPHostName which makes use of ::DnsQuery() and CVerifySMTPEmailAddress which does the actual email validation. It should be noted that I decided to split the classes up into two distinct classes because of the way that I intend to use them but they could be combined into a single class. Below I give a brief description of each.

CGetSMTPHostName

The CGetSMTPHostName class provides three member functions: GetSmtpHostName(), ResetHostMap() and Dump(). It also contains a std::map that holds the DomainName and SMTPHostName pair.

CGetSMTPHostName::GetSmtpHostName()

This method accepts an email address and a CString& to return the host name for the email address. The host name is found using the ::DNSQuery() function. The function starts by stripping the Domain part of the email address and looking in our std::map to determine if we have previously performed a lookup on this domain. If so, we return the host name and we are done. If not, then we make a call to ::DNSQuery() to determine the hostname. If the call is successful we insert the domain and hostname pair into the std::map and return. Here's the code:
BOOL CGetSMTPHostName::GetSmtpHostName(CString _EmailAddress, <BR>                                       CString& _HostName)
{
    BOOL bRV = TRUE;
    _HostName.Empty();
    int start = _EmailAddress.Find('@')+1;
    CString strDomain<BR>                   = _EmailAddress.Mid(start,_EmailAddress.GetLength()-start);
    if( ! strDomain.IsEmpty())
    {
         // First, look in our map to see if we have looked up this SMTP <BR>         // 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()

This method is nothing more than a utility function to clear the std::map in the event that you need to start fresh.

CGetSMTPHostName::Dump()

Another utility function to print the the console the list of domains and hostnames that are contained within the std::map.

CVerifySMTPEmailAddress

This class contains (has a) CGetSMTPHostName class as a private member and had a single public method called VerifyEmailAddress() shown below:
BOOL CVerifySMTPEmailAddress::VerifyEmailAddress(CString _EmailAddress)
{
    CString strHostName;
    if(m_GetSmtpHostName.GetSmtpHostName(_EmailAddress, strHostName))    
    {
    return(Connect(strHostName, _EmailAddress));
    }
    return(FALSE);
}

main() or _tmain()

Here's the main function of the console application:
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" <BR>                      << std::endl;
        }
        else
        {
        std::cout << strSMTPAddress.GetBuffer(0) << vrfyemail.GetLastError() <BR>                  << std::endl;
        }
        strSMTPAddress.Empty();
        }
    }
    return nRetCode;
}

Notes

::DNSQuery()[^] can be used for much more than MX Record lookups. Information can be found on MSDN (click the link).

I prefer to use #pragma comment to link in libraries, especially on demonstration applications such as this. You can set up the link libraries to suit your taste.

Conclussion

I wrote this article for one purpose and that was to show that the libraries provided by Microsoft are bountiful. So before you start writing a DNS MX Record lookup function or the like take a look in MSDN or ask a living MSDN index (a.k.a. James) if an existing library contains the functionality that you need.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Dave Loeser
Web Developer
United States United States
Dave has been programming for the past 20+ years first on a variety of platforms and operating systems using various languages. As a hobbyist Dave cut his teeth on the Commodore Pet and the 64 coding in basic and then moving to 6502 ASM. Dave moved to the Amiga using 68000 ASM and then C. His knowledge of the C language offered the stepping stone for him to make his hobby his profession taking a position coding C on an AIX Unix platform. Since then he has worked on many flavors of Unix, QNX, Windows (3.11 – present), and has been coding games for his Pocket PC in his spare time.

Dave lives in Indiana with his two teenage daughters and two cats.

Comments and Discussions

 
Generalnice job Pinmemberskumria5-Sep-06 9:58 
QuestionDnsQuery API timeout? Pinsussel1215-Aug-05 0:46 
GeneralDnsQuery ErrorCode 9002 Pinmember_happymozart_11-May-05 10:06 
GeneralDnsQuery() Is a very dependent function PinmemberG_S14-Feb-05 14:37 
GeneralDNS adding/modifying zone records Pinmemberkumatbp10-Oct-04 18:24 
GeneralDNS adding/modifying zone records Pinmemberkumatbp10-Oct-04 18:24 
Generalthanks, before i use udp and tcp to query it PinmemberSevenCat25-Oct-03 0:17 
Generalwrite some code, compare the Preference(rfc requir this)) PinmemberSevenCat27-Oct-03 19:33 
GeneralDNSQuery not available on Win9x PinmemberMarc G4-Sep-03 5:05 
Questionhow to get more than one mx records? Pinmemberbborn12-Aug-03 21:18 
AnswerRe: how to get more than one mx records? PinmemberPaul Ingles25-Oct-03 1:36 
GeneralJust being picky ;-) Pinmemberpierrec16-Jul-03 6:04 
QuestionCan i use to query spamcop.net ? PinmemberScorpioMidget21-May-03 6:52 
GeneralLinker error PinmemberAnthony_Yio2-Mar-03 17:58 
GeneralRe: Linker error PinmemberAnthony_Yio2-Mar-03 18:04 
Generalspam Pinmemberzoldat2-Mar-03 16:40 
GeneralRe: spam Pinmemberjeoshah19-Jun-03 2:13 
GeneralGood attempt, but.... Pinmemberhector santos1-Mar-03 3:16 
GeneralRe: Good attempt, but.... Display Correction Pinmemberhector santos1-Mar-03 3:20 
GeneralRe: Good attempt, but.... Display Correction PinmemberGisle Vanem1-Mar-03 3:45 
IMHO, it's better to use "VRFY <addess>" first.
If that fails, then use your method.


Gisle V.

"If you feel paranoid it doesn't mean they're not after you!" -- Woody Allen
GeneralRe: Good attempt, but.... Display Correction Pinmemberhector santos1-Mar-03 4:12 
GeneralRe: Good attempt, but.... Display Correction Pinmembershankargiri8-Feb-11 8:55 
GeneralRe: Good attempt, but.... PinmemberDave Loeser1-Mar-03 5:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150414.1 | Last Updated 28 Feb 2003
Article Copyright 2003 by Dave Loeser
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid