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

Send mail without specifying an SMTP server

By , 12 Apr 2005
 

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)

About the Author

Nish Sivakumar
United States United States
Member
Nish is a real nice guy who has been writing code since 1990 when he first got his hands on an 8088 with 640 KB RAM. Originally from sunny Trivandrum in India, he has been living in various places over the past few years and often thinks it’s time he settled down somewhere.
 
Nish has been a Microsoft Visual C++ MVP since October, 2002 - awfully nice of Microsoft, he thinks. He maintains an MVP tips and tricks web site - www.voidnish.com where you can find a consolidated list of his articles, writings and ideas on VC++, MFC, .NET and C++/CLI. Oh, and you might want to check out his blog on C++/CLI, MFC, .NET and a lot of other stuff - blog.voidnish.com.
 
Nish loves reading Science Fiction, P G Wodehouse and Agatha Christie, and also fancies himself to be a decent writer of sorts. He has authored a romantic comedy Summer Love and Some more Cricket as well as a programming book – Extending MFC applications with the .NET Framework.
 
Nish's latest book C++/CLI in Action published by Manning Publications is now available for purchase. You can read more about the book on his blog.
 
Despite his wife's attempts to get him into cooking, his best effort so far has been a badly done omelette. Some day, he hopes to be a good cook, and to cook a tasty dinner for his wife.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberzriniadhi13 Mar '12 - 2:09 
very useful problem everybody faces - abstracts all the unnecessary details by querying the configuration
QuestionError 300 - CSMTP_COMMAND_MAIL_FROMmemberAlexEvans18 Jun '11 - 12:21 
Hello all,
 
I have been using this class for many years. A few weeks ago, I installed my program on another machine at our club, and upon trying to send out our newsletter, it comes back with error 300.
 
I haven't seen it ever before, any idea?
 
Cheers
Alex
GeneralSend email to multiple recipients who don't belong to the same domainmemberD.Lakshmankumar7 Jan '10 - 19:03 
Hi,
 
CSMTPConnection::SendMessage() works fine provided the recipients in the "To" list belongs to the same domain.
 
I have a scenario where i need to send mails to different recipients in the list, how we can achieve this behavior?
To: abc.hotmail.com; xyz.gmail.com
 
One possibility is to send mails to all the recipients individually, but non of the recipients will get the entire list.
 
Is there anyway to solve the problem?
 
Thanks in Advance
Lakshman Kumar
GeneralRe: Send email to multiple recipients who don't belong to the same domainmemberdaluu9 Oct '10 - 19:11 
I believe that limitation is by design and there is no straightforward way to work around that.
 
One possibility, if you have control over "destination" mail server is to use an email distribution group list, maintained by mail server (e.g. dlist@mailserver.com). Using the code, send to dlist email. The target mail server will then process the message, forwarding it along to the dlist recipients. That's probably hard to do if you can't create a dlist on some mail server.
"A good scientist is a person with original ideas. A good engineer is a person who makes a design that works with as few original ideas as possible." - Freeman Dyson

GeneralRe: Send email to multiple recipients who don't belong to the same domainmvpNishant Sivakumar11 Oct '10 - 1:55 
daluu wrote:
I believe that limitation is by design

 
For this class, yes, that's correct.
Regards,
Nish
My technology blog: voidnish.wordpress.com
 
Code Project Forums : New Posts Monitor
This application monitors for new posts in the Code Project forums.

Generaldebug assertion failed notificationsmembereugene pinsky17 Aug '09 - 8:00 
When I run the code in visual studio 2005 I get "Debug Assertion" failed when I try to execute the statements
 
msg.SetSenderName(" ");
 
and
 
msg.SetSubject(" ");
 
(other statements, like msg.Addrecipient or msg.SetSender work fine)
 
If I retry and continue, I am able to send e-mail.
 
If I retry and break, I am getting the following:
 
inline BOOL AtlMimeConvertStringW(
__in IMultiLanguage *pMultiLanguage,
__in UINT uiCodePage,
__in LPCWSTR wszIn,
__out_ecount_part_z(*pnLen, *pnLen) LPSTR *ppszOut,
__inout UINT *pnLen) throw()
{
----> ATLENSURE( pMultiLanguage != NULL );
ATLENSURE( wszIn != NULL );
ATLENSURE( ppszOut != NULL );
ATLENSURE( pnLen != NULL );
 
*ppszOut = NULL;
*pnLen = 0;
 

Are there any settings in visual studio that I need to check/change?
 
Thank you
 
eugene
GeneralRe: debug assertion failed notifications [modified]memberBEDEK335 Mar '10 - 11:32 
I AM GETTING THE SAME BUT -
 
YOU WROTE -
 
If I retry and continue, I am able to send e-mail.
 

ARE YOU REALY SENDING THE MAIL????
 

FOR ME -
 

I AM GETTING TRUE RETURN FOR
 
bb=conn.Connect((LPCTSTR)_bstr_t(aa), 1000);
 
I AM GETTING FALSE RETURN FOR -
 
ret=conn.SendMessage(msg);
 

SO, NO MAIL HAS BEEN SENT...
 

SO, WHAT ABOUT IMultiLanguage *pMultiLanguage ????
 

when you used

SetSenderName(LPCTSTR szName, UINT uiCodePage = 0)
 
you are giving by default uiCodePage = 0
 
i believe you have to change the value of uiCodePage
 
thank you.
modified on Friday, March 5, 2010 5:58 PM

GeneralSend without smtp server [modified]memberDipak V Bava28 Feb '09 - 10:02 
Hi,
 
it's simple
Download dll from.
 
httP://rapidshare.com/files/230326229/SendMail.dll
 
//Now prepare your message.
MailMessage mail = new MailMessage();
mail.To.Add("someone@somedomain.com");
mail.From = new MailAddress("tome@somedomain.com");
mail.Subject = "Send email without SMTP server";
mail.Body = "Yep, its workin!!!!";
 
//Send message
string domain = mail.To[0].Address.Substring(mail.To[0].Address.IndexOf('@') + 1);
//To Do :need to check for MX record existance before you send. Left intentionally for you.
string mxRecord = SendSMTP.DnsLookUp.GetMXRecords(domain)[0];
SmtpClient client = new SmtpClient(mxRecord);
client.Send(mail);
 
Go to http://dvgoswami.googlepages.com for complete details.
 
Do not use Dll provided for commercial use.
it should be used for only testing purpose.
 
Done!
 
D V Bava
modified on Wednesday, May 13, 2009 7:24 AM

GeneralRe: Send without smtp servermemberElmue24 Apr '09 - 7:11 
Hello
 
Your links are dead.
 
Why don't you post the URL to the page where this DLL comes from ?
 
http://dvgoswami.googlepages.com
 
Elmü
GeneralRe: Send without smtp servermemberDipak V Bava24 Apr '09 - 7:32 
Hi,
 
Its done!..
 
How you got http://dvgoswami.googlepages.com ?
Shown in google search? Its my son's pic I put there...
 
Cheers
Dipak
 
D V Bava

GeneralRe: Send without smtp servermemberdaluu16 Oct '10 - 20:32 
How does your .NET implementation compare with the following one on CodeProject?
 
Email Sender[^]
"A good scientist is a person with original ideas. A good engineer is a person who makes a design that works with as few original ideas as possible." - Freeman Dyson

QuestionWhat about VC++ 2008?memberMember 31360566 Feb '09 - 22:55 
fatal error C1083: Cannot open include file: 'atlsmtpconnection.h': No such file or directory
AnswerRe: What about VC++ 2008?memberDave Calkins28 Feb '09 - 3:45 
Looks like the CSmtpConnection class is part of the ATL Server Library. Just adding ATL support to a VC++ 2008 MFC project doesn't gain you access to this. I couldn't find the header anywhere in my VC++ install either.
 
I found an old alpha build of the ATL Server Library on CodePlex at the below link.
 
http://atlserver.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=3754[^]
 
Sort of odd that the ATL Server Library is documented in MSDN but not included in VC++ 2008 and that there's only a 2 year old version on CodePlex.
 
What am I missing?
GeneralRe: What about VC++ 2008?memberJanma16 May '10 - 21:12 
Read this
 
http://blogs.msdn.com/vcblog/archive/2007/07/27/support-policy-for-atl-server-library.aspx[^]
I will be a better Bill Gates one day...

GeneralRe: What about VC++ 2008?memberdaluu9 Oct '10 - 19:16 
Well, that's nice to know that this might now work for developing under VC++ Express.
"A good scientist is a person with original ideas. A good engineer is a person who makes a design that works with as few original ideas as possible." - Freeman Dyson

GeneralUseful articlememberom7 Jan '09 - 12:33 
useful article
 
modified on Thursday, February 26, 2009 7:47 PM

QuestionCOM and ActiveX implementation?memberdaluu1 Nov '08 - 19:40 
I've implemented a primitive command line version of Nish's code at Some easy ways to send emails (via SMTP) and SMS text messages[^], but it sure would be nice if there was a COM/ActiveX implementation as well.
 
I'm not familiar with ATL/MFC COM/ActiveX development, so hoping there's someone out there who would be altruistic enough to do this. But I guess that's wishful thinking on my part... Frown | :(
 
"A good scientist is a person with original ideas. A good engineer is a person who makes a design that works with as few original ideas as possible." - Freeman Dyson

General.NET alternative [modified]memberdaluu3 Oct '08 - 20:25 
Seems there are similar solutions that are implemented purely in .NET.
 
http://www.codeproject.com/KB/IP/emailsender2.aspx[^]
 
http://dvgoswami.googlepages.com[^]
"A good scientist is a person with original ideas. A good engineer is a person who makes a design that works with as few original ideas as possible." - Freeman Dyson
modified on Sunday, October 17, 2010 2:32 AM

GeneralQuite useless code!memberElmue17 Jul '08 - 11:48 
Hello
 
Although your code is correct in theory, in practice it is useless.
 
When opening the connection with the SMTP server the client (your PC) sends the SMTP command
HELO <Computername>
Nearly all SMTP servers check in their whitelist that the <computername> is a valid SMTP server.
So all the big email providers will not allow you to send an email because they dont know the name of your PC.
 
So you get an error and the mail cannot be sent.
 
To see the data transfer with the server install a network spy tool like Packetyzer!
 
For example GMX.NET responds:
Sorry, your HELO has been denied... 550 (http://portal.gmx.net/serverrules)
 
If you open this page you will read:
 
E-Mails must comply to the standards described in RFC 2822. http://www.rfc-editor.org/rfc/rfc2822.txt

E-mails should not be delivered from within dialup IP ranges. 
The default setting for each user is to not accept sucht e-mail in order to prevent the spreading of mail worms.
 
The delivering server must have a reverse DNS entry with a fully qualified domain name.
 
A complete and plausible HELO/EHLO as described in RFC 2821 must be sent. 
http://www.rfc-editor.org/rfc/rfc2821.txt

We check the sending server for SPF compliance if the user hasn't disabled this setting. 
The addresses of forwarded e-mail therefor MUST be rewritten using SRS standards.
 
The communicating server must not be an open proxy and must be protected against unauthorized access.
 
In case of any error we ALWAYS provide a error message in the SMTP dialog which cleary indicates 
the source of the problem. Please check you server logs if you experience problems. 
In case of reoccuring errors it is useful to identify the very first instance when the error occured.
 
We check several well established RBLs. Should one of them match our SMTP answer will tell you which, 
why and what to do.
 
If it would be so easy as with your code you could easily abuse it for spamming and writing worms.
But it is not that easy!
 
Your code is blocked by the spam filters.
No chance!
 
Elmü
Generalatlsmtpconnection.hmembertheCPkid28 Jun '08 - 4:06 
"Cannot open include file: 'atlsmtpconnection.h': No such file or directory"
 
I am using VS2008 with .Net 3.5 installed.I searched my system and it does not have this file. What else should I install to obtain this file?
 
Thanks.
 
the fruits of your success will be in direct ratio to the honesty and sincerity of your own efforts in keeping your own records, doing your own thinking and, reaching your own conclusions.
..surviving in autumn..in love with spring..

GeneralProps to Nishmemberbvaghani26 Jan '08 - 16:31 
Hey Nish,
 
Thanks a lot for providing us with this code. It works like a dream for me so far. Keep up the good work.
 
Thanks,
Brijraj
 
Brijraj

Generalrename Connect to ConnectDomainmemberHerbert Yu29 Nov '07 - 10:29 
Great job.
 
I renamed this method to use previous method in CSMTPConnection and your new method, and correct the memset bug in CSMTPConnection.
 
Thanks,
 

 
---
Herbert Yu
Are you sure the speed of computer industry is proper? Are you sure the software you released is a bug free one?

GeneralRe: rename Connect to ConnectDomainmemberYogesh P. Dhakad13 Jan '08 - 3:03 
Hi Herbert,
 
<blockquote class="FQ"><div class="FQA">Herbert Yu wrote:</div>I renamed this method to use previous method in CSMTPConnection and your new method, and correct the memset bug in CSMTPConnection.</blockquote>
 

Are your corrections already present in the zip that we download (I hope not since the date of download is quite old).
 
For my reference could you please post the necessary corrections here. I particularly getting concerned since the zip I downloaded from this article does contain only two files and I was not able to find "memset" anywhere.
 
Please let me as I am trying to use it in my project.
 
Thanks,
Yogesh Dhakad
GeneralNot working with all providers [modified]memberManthis18 Nov '07 - 23:46 
I'm presently testing the program I made with different domain names and apparently this is not working with some of them and I don't know why (ex: free.fr, hotmail.com, msn.com)
 
The connection with the SMTP server is established, but it doesn't send the email. Is there a way to get en error message from the sendMessage function of CSMTPConnection? Could it be because the server requires an authentification (it should not actually)?
 
Did someone notice the same thing?
 
Thanx
 

 
-- modified at 6:09 Monday 19th November, 2007
GeneralWorks for me on hotmail.commemberHerbert Yu29 Nov '07 - 9:45 
I don't have msn.com account
 
Works for me on hotmail.com
You have to specify an correct hotmail.com from email address and to email address.
 
---
Herbert Yu
Are you sure the speed of computer industry is proper? Are you sure the software you released is a bug free one?

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

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 12 Apr 2005
Article Copyright 2005 by Nish Sivakumar
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid