![]() |
General Programming »
Programming Tips »
General
Intermediate
License: The Microsoft Public License (Ms-PL)
Send mail without specifying an SMTP serverBy Nishant SivakumarA class derived from CSMTPConnection that queries the MX record for a target domain and uses that to send mail |
VC7, VC7.1Win2K, WinXP, Win2003, Visual Studio, ATL, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
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.
#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(); }
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)
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.
/* 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); };
/* 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); } }
As usual, feedback is welcome and appreciated whether it's constructive or not.
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 12 Apr 2005 Editor: Nishant Sivakumar |
Copyright 2005 by Nishant Sivakumar Everything else Copyright © CodeProject, 1999-2009 Web16 | Advertise on the Code Project |