Click here to Skip to main content
15,881,882 members
Articles / Desktop Programming / ATL
Article

Send mail without specifying an SMTP server

Rate me:
Please Sign up or sign in to vote.
4.76/5 (44 votes)
12 Apr 2005Ms-PL2 min read 1.3M   5.4K   114   142
A class derived from CSMTPConnection that queries the MX record for a target domain and uses that to send mail

Overview

Quite frequently, you hear people asking how they can send an email from their applications to a specific email address without prompting the user for a relaying SMTP server. The most commonly suggested solution is to use MAPI and get a list of SMTP servers from the user's registry, but this assumes that the user has configured a MAPI compliant email client on his machine. I always reply with my solution of querying the MX record for the target domain and then SMTP-chatting to that server directly - it's easy to do, it works on any machine and it's also the fastest way to send email (minimum number of SMTP hops).

Starting with VC++ 7, ATL includes the CSMTPConnection class which lets you send mail, provided you give it an SMTP server to connect to. I derived a class (CSMTPConnection2) from CSMTPConnection which lets you pass in the target domain name directly and the class queries the MX records using the default DNS on the client machine, gets a list of SMTP servers (depending on the number of MX records returned) and connects to the first SMTP server that works okay. The only visible change is to the Connect method, and even for the Connect method, the method signature remains the same. The first parameter (an LPCTSTR) now represents the target domain name instead of the SMTP hostname. So it should be pretty easy to modify your existing code. Just change all references to CSMTPConnection in your code to CSMTPConnection2 and you are done.

Using the class

  • #include the header file for the class

    #include "smtpconnection2.h"

    The header file includes a #pragma linker directive to include Dnsapi.lib

  • Use the CSMTPConnection2 class just as you would use the CSMTPConnection class (it's assumed that CoInitialize has been called prior to invoking and using this class)

    CMimeMessage msg;
    msg.SetSender("nish@somedomain.com");
    msg.SetSenderName("Nishter");
    msg.AddRecipient("someone@vsnl.com");
    
    //Optional
    msg.SetSubject("Hello World");
    msg.AddText("Hmmm, this should work fine!");
    //msg.AttachFile("some file path");
    
    CSMTPConnection2 conn;
    //You need to specify the domain name of the recipient email address
    if(conn.Connect("vsnl.com"))
    {
        if( conn.SendMessage(msg) == TRUE )
            std::cout << "Mail sent successfully" << std::endl;
        conn.Disconnect();    
    }

Class requirements

  • You'll need VC++ 7 or above (for the ATL classes)

  • This code will run only on Windows 2000 or later (because of the DNS API that's used to query the MX record)

  • You do not need MFC (the CString that's used is shared between MFC/ATL and I specifically used CSimpleArray instead of an MFC array class)

Limitation

Note that, because the class looks up the MX record and SMTPs directly into the mail server for each domain name, you cannot use this class to send mails to multiple-domains in one go.

Source listings

Header file

/*
    Copyright(C) Nishant Sivakumar (nish#voidnish.com)
    Please maintain this copyright notice if you distribute this file
    in original or modified form.
*/

#pragma once
#include <atlsmtpconnection.h>
#include <Windns.h>

#pragma comment(lib,"Dnsapi.lib")

class CSMTPConnection2 : public CSMTPConnection
{
public:    
    BOOL Connect(LPCTSTR lpszHostDomain, DWORD dwTimeout = 10000) throw();
private:
    void _GetSMTPList(LPCTSTR lpszHostDomain, CSimpleArray<CString>& arrSMTP);
}; 

Cpp file

/*
    Copyright(C) Nishant Sivakumar (nish#voidnish.com)
    Please maintain this copyright notice if you distribute this file
    in original or modified form.
*/

#include "StdAfx.h"
#include "smtpconnection2.h"

BOOL CSMTPConnection2::Connect(LPCTSTR lpszHostDomain, 
                               DWORD dwTimeout /*= 10000*/) throw()
{
    CSimpleArray<CString> arrSMTP;
    _GetSMTPList(lpszHostDomain, arrSMTP);
    for(int i=0; i<arrSMTP.GetSize(); i++)
    {
        if(CSMTPConnection::Connect(arrSMTP[i], dwTimeout) == TRUE)
            return TRUE;
    }
    return FALSE;
}

void CSMTPConnection2::_GetSMTPList(LPCTSTR lpszHostDomain, 
                                   CSimpleArray<CString>& arrSMTP)
{
    PDNS_RECORD pRec = NULL;
    if(DnsQuery(lpszHostDomain, DNS_TYPE_MX, DNS_QUERY_STANDARD,
        NULL, &pRec, NULL) == ERROR_SUCCESS)
    {
        PDNS_RECORD pRecOrig = pRec;
        while(pRec)
        {
            if(pRec->wType == DNS_TYPE_MX)
                arrSMTP.Add(pRec->Data.MX.pNameExchange);
            pRec = pRec->pNext;
        }
        DnsRecordListFree(pRecOrig,DnsFreeRecordList);
    }
} 

Conclusion

As usual, feedback is welcome and appreciated whether it's constructive or not.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
United States United States
Nish Nishant is a technology enthusiast from Columbus, Ohio. He has over 20 years of software industry experience in various roles including Chief Technology Officer, Senior Solution Architect, Lead Software Architect, Principal Software Engineer, and Engineering/Architecture Team Leader. Nish is a 14-time recipient of the Microsoft Visual C++ MVP Award.

Nish authored C++/CLI in Action for Manning Publications in 2005, and co-authored Extending MFC Applications with the .NET Framework for Addison Wesley in 2003. In addition, he has over 140 published technology articles on CodeProject.com and another 250+ blog articles on his WordPress blog. Nish is experienced in technology leadership, solution architecture, software architecture, cloud development (AWS and Azure), REST services, software engineering best practices, CI/CD, mentoring, and directing all stages of software development.

Nish's Technology Blog : voidnish.wordpress.com

Comments and Discussions

 
GeneralRe: SetSenderName and SetSubject won't work...? Pin
rpna11-Jul-06 16:41
rpna11-Jul-06 16:41 
GeneralSend Bulk email Pin
Maulik Pandya22-Jun-05 1:00
Maulik Pandya22-Jun-05 1:00 
Generalcontent-type: text/html Pin
ridopark14-Jun-05 13:46
ridopark14-Jun-05 13:46 
QuestionDiffrent port? Pin
Y_R11-Jun-05 0:00
Y_R11-Jun-05 0:00 
GeneralUsing in separate thread Pin
_Christian11-May-05 23:50
_Christian11-May-05 23:50 
GeneralRe: Using in separate thread Pin
3m2u19-Mar-06 22:44
3m2u19-Mar-06 22:44 
GeneralRe: Using in separate thread [modified] Pin
djjj0626-Aug-06 6:17
djjj0626-Aug-06 6:17 
GeneralFirst generation SPAM tool Pin
Peter Ritchie21-Apr-05 17:32
Peter Ritchie21-Apr-05 17:32 
GeneralRe: First generation SPAM tool Pin
Nish Nishant22-Apr-05 21:24
sitebuilderNish Nishant22-Apr-05 21:24 
GeneralRe: First generation SPAM tool Pin
S. Senthil Kumar22-Apr-05 22:34
S. Senthil Kumar22-Apr-05 22:34 
GeneralRe: First generation SPAM tool Pin
Andreas Kroll24-Apr-05 0:32
Andreas Kroll24-Apr-05 0:32 
GeneralDnsQuery Pin
DiegoDevesa21-Apr-05 7:17
DiegoDevesa21-Apr-05 7:17 
GeneralRe: DnsQuery Pin
DiegoDevesa21-Apr-05 7:46
DiegoDevesa21-Apr-05 7:46 
GeneralDynIP and MX sending issue! Pin
c2j221-Apr-05 1:01
c2j221-Apr-05 1:01 
GeneralRe: DynIP and MX sending issue! Pin
Nish Nishant21-Apr-05 1:37
sitebuilderNish Nishant21-Apr-05 1:37 
GeneralRe: DynIP and MX sending issue! Pin
c2j221-Apr-05 1:52
c2j221-Apr-05 1:52 
GeneralRe: DynIP and MX sending issue! Pin
Nish Nishant21-Apr-05 2:41
sitebuilderNish Nishant21-Apr-05 2:41 
GeneralQuestions about the IP-Port(s) Pin
Stephan Pilz20-Apr-05 0:20
Stephan Pilz20-Apr-05 0:20 
GeneralRe: Questions about the IP-Port(s) Pin
Nish Nishant20-Apr-05 2:13
sitebuilderNish Nishant20-Apr-05 2:13 
GeneralC# Version Pin
Saraceen19-Apr-05 22:10
Saraceen19-Apr-05 22:10 
Generalhelp needed3 Pin
_tasleem19-Apr-05 17:03
_tasleem19-Apr-05 17:03 
GeneralRe: help needed3 Pin
Nish Nishant19-Apr-05 22:40
sitebuilderNish Nishant19-Apr-05 22:40 
Generalhelp needed2 Pin
_tasleem18-Apr-05 16:44
_tasleem18-Apr-05 16:44 
GeneralRe: help needed2 Pin
Nish Nishant18-Apr-05 17:37
sitebuilderNish Nishant18-Apr-05 17:37 
QuestionGet the domain name automatically? Pin
AndrewSmirnov18-Apr-05 4:04
AndrewSmirnov18-Apr-05 4:04 

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

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