Remember CDOSYS, and some C++ code
CDOSYS is one of those Microsoft technologies that was designed to correct problems with an earlier product that never worked quite right but obviously generated a hefty following because it happened to be there in the default OS install. The problem is that few people even know CDOSYS even exists - some developers are still using CDONTS as a simple SMTP transport on Windows 2000. Yuck.
If you don't know what CDOSYS is and you're still using CDONTS (or something worse), I recommend you read the documentation and feel the love. CDOSYS is the absolute best general-purpose SMTP component I've ever used. And trust me, I've used a few. And — get this — it even supports NNTP! When you post to a Microsoft newsgroup using the web-based interface, guess what you're using? Yep, CDOSYS! It's a cool library. It just takes a few tries to get right.
Aside from not being exactly advertised by Microsoft, CDOSYS has another problem: It's confusing. The object model is a bit wacky compared to similar Windows components because it's based on a collection model that uses XML schema names (!) as property key identifiers, some of which have matching names constants. But not all of them. So it can be a tad daunting to get into it at first. But eventually it all becomes clear... after banging your head on the keyboard for a few hours. Essentially, a CDO.Message object has some top-level
properties that you can use to set delivery and formatting options, and a child object called Configuration that is actually an ADO recordset, whose fields in turn contain more esoteric properties. Sounds simple, eh?
Incidentally, the .NET System.Web.Mail namespace uses CDOSYS as well (and that's why it's not supported under Win98 or NT4). The System.Web.Mail.MailMessage object however maps the Configuration objects through a string dictionary called Headers, which makes sense if you think about it having to support some future underlying SMTP provider. Or something.
For VB6, the process is basically the same as the C++ code below, with the added simplicity of just setting a reference to "CDO for Windows 2000" and not having to muck around with variant_t's and all that ugly stuff.
But the code. Yes, this is a sample of a console app that will send an HTML-formatted email to someone. Why C++? Because I had a ton of fun figuring out how to do it, that's why.
#define UNICODE
#define _UNICODE
#define _WIN32_WINNT 0x0500
#define _WIN32_IE 0x0600
#include <iostream>
#include <tchar.h>
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS
#include <atlbase.h>
#include <comdef.h>
#include <cdosys.h>
#include <cdosyserr.h>
int _tmain(int argc, _TCHAR* argv[])
{
CComPtr<CDO::IMessage> msg;
CComPtr<CDO::IConfiguration> config;
CComPtr<CDO::Fields> fields;
CComPtr<CDO::Field> field;
variant_t vValue;
variant_t vField;
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
msg.CoCreateInstance(_T("CDO.Message"));
// To, Cc, Bcc. Only "To" is required.
msg->put_To(_T("RMS <rms@fsf.org>"));
msg->put_CC(_T("Zealotz Unlimited \
<vivalarevolucion@linux.net"));
msg->put_BCC(_T("The Internet <everyone@net.net">));
// Only "From" is required.
msg->put_From(_T("Concerned Customer <bork@vbbox.com>"));
msg->put_Organization(_T("The Center For Rational Thought (TM)"));
msg->put_ReplyTo(_T("support@ibm.com"));
// Automatically generate plain text body from
// the MIME HTML content
msg->put_AutoGenerateTextBody(TRUE);
msg->put_Subject(_T("Don't send flowers"));
msg->put_MimeFormatted(TRUE);
msg->put_HTMLBody(_T("<html><head> <title>Hello</title></head>
<body>I send you this file in order to have your advice.
</body></html>"));
// OK now, let's get the Configuration recordset
// and its Fields collection.
msg->get_Configuration(&config);
config->get_Fields(&fields);
// Send using (port, pickup)
vField = cdoSendUsingMethod;
fields->get_Item(vField, &field);
vValue = (long)CDO::cdoSendUsingPort;
field->put_Value(vValue);
field.Release();
// SMTP Server
vField = cdoSMTPServer;
fields->get_Item(vField, &field);
vValue = _T("mysmtpserver.com");
field->put_Value(vValue);
field.Release();
// SMTP port. Nominally 25
vField = cdoSMTPServerPort;
fields->get_Item(vField, &field);
vValue = _T("25");
field->put_Value(vValue);
field.Release();
// Importance
fields->get_Item(variant_t(cdoImportance), &field);
vValue = (long)CDO::cdoHigh; // in CDO::cdoImportanceValues
field->put_Value(vValue);
field.Release();
// Make sure the message sees the changes.
fields->Update();
// And away we go.
msg->Send();
CoUninitialize();
return 0;
}
I won't go too deep into this, but if you're familiar with SMTP and mail in general you'll recognize what the code is doing. I will mention that CDOSYS can use the IIS-hosted SMTP pickup service by omitting the target SMTP host and port. The trick is of course to have the SMTP server running and configured with the correct "smart host". This also has the benefit of queuing messages in case the SMTP relay is down or unreachable for some reason.
If you're writing an application that runs in your company's intranet with an Exchange server that has SMTP support enabled, this code will work fine. You can even send mail to distribution lists using the canonical $LISTNAME@thedomain.com.