You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
384 lines
12 KiB
384 lines
12 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
mail.cpp
|
|
|
|
Abstract:
|
|
|
|
Implementation of mail related utility functions
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY) Feb, 2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <faxutil.h>
|
|
|
|
#pragma warning (disable:4146) // unary minus operator applied to unsigned type, result still unsigned
|
|
#include "msado15.tlh"
|
|
#include "cdosys.tlh"
|
|
#include <cdosysstr.h> // String constants in this file
|
|
#include <cdosyserr.h> // Error constants in this file
|
|
#pragma warning (default:4146) // unary minus operator applied to unsigned type, result still unsigned
|
|
|
|
#define SMTP_CONN_TIMEOUT (long)10 // Time out (sec) of SMTP connection
|
|
|
|
HRESULT
|
|
SendMail (
|
|
LPCTSTR lpctstrFrom,
|
|
LPCTSTR lpctstrTo,
|
|
LPCTSTR lpctstrSubject,
|
|
LPCTSTR lpctstrBody,
|
|
LPCTSTR lpctstrHTMLBody,
|
|
LPCTSTR lpctstrAttachmentPath,
|
|
LPCTSTR lpctstrAttachmentMailFileName,
|
|
LPCTSTR lpctstrServer,
|
|
DWORD dwPort, // = 25
|
|
CDO_AUTH_TYPE AuthType, // = CDO_AUTH_ANONYMOUS
|
|
LPCTSTR lpctstrUser, // = NULL
|
|
LPCTSTR lpctstrPassword, // = NULL
|
|
HANDLE hLoggedOnUserToken // = NULL
|
|
)
|
|
/*++
|
|
|
|
Routine name : SendMail
|
|
|
|
Routine description:
|
|
|
|
Sends a mail message using SMTP over CDO2.
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), Feb, 2000
|
|
|
|
Arguments:
|
|
|
|
lpctstrFrom [in] - From address (mandatory)
|
|
e.g: [email protected]
|
|
lpctstrTo [in] - To address (mandatory)
|
|
e.g: [email protected]
|
|
lpctstrSubject [in] - Subject (optional)
|
|
lpctstrBody [in] - Body text of message (optional).
|
|
If NULL, the message will not have a body.
|
|
lpctstrHTMLBody [in] - HTML Body text of message (optional).
|
|
If NULL, the message will not have a HTML body.
|
|
lpctstrAttachmentPath [in] - Full path to file to attach (optional)
|
|
If NULL, the message will not include attachments.
|
|
lpctstrAttachmentMailFileName [in] - The file name of the attachment as is will appear in the mail message.
|
|
lpctstrServer [in] - SMTP server to connect to (mandatory)
|
|
e.g: hai-msg-01
|
|
dwPort [in] - SMTP port (optional, default = 25)
|
|
AuthType [in] - Type of SMTP authentication.
|
|
Valid values are CDO_AUTH_ANONYMOUS, CDO_AUTH_BASIC,
|
|
and CDO_AUTH_NTLM.
|
|
lpctstrUser [in] - User to authenticate
|
|
In use only if AuthType is CDO_AUTH_BASIC or CDO_AUTH_NTLM.
|
|
lpctstrPassword [in] - Password to authenticate
|
|
In use only if AuthType is CDO_AUTH_BASIC or CDO_AUTH_NTLM.
|
|
hLoggedOnUserToken [in] - Handle to alogged on user token.
|
|
In use only if AuthType is CDO_AUTH_NTLM.
|
|
|
|
Return Value:
|
|
|
|
Standard HRESULT code
|
|
|
|
--*/
|
|
{
|
|
DEBUG_FUNCTION_NAME(TEXT("SendMail"))
|
|
|
|
Assert (lpctstrFrom && lpctstrTo && lpctstrServer);
|
|
HRESULT hr = NOERROR;
|
|
Assert ((CDO_AUTH_ANONYMOUS == AuthType) ||
|
|
(CDO_AUTH_BASIC == AuthType) ||
|
|
(CDO_AUTH_NTLM == AuthType));
|
|
BOOL bImpersonated = FALSE;
|
|
|
|
|
|
hr = CoInitialize(NULL);
|
|
if (S_FALSE == hr)
|
|
{
|
|
//
|
|
// Thread's COM already initialized.
|
|
// This is not an error and we still have to call CoUninitialize at the end.
|
|
//
|
|
hr = NOERROR;
|
|
}
|
|
if (FAILED(hr))
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("CoInitialize failed. (hr: 0x%08x)"),
|
|
hr);
|
|
return hr;
|
|
}
|
|
try
|
|
{
|
|
//
|
|
// The following code is in a seperate block so that the auto pointers dtors
|
|
// get called before CoUninitialize
|
|
//
|
|
|
|
//
|
|
// Create a new message instance (can throw exception)
|
|
//
|
|
IMessagePtr iMsg(__uuidof(Message));
|
|
//
|
|
// Create a new CDO2 configuration instance (can throw exception)
|
|
IConfigurationPtr iConf(__uuidof(Configuration));
|
|
//
|
|
// Access configuration fields collection
|
|
//
|
|
FieldsPtr Flds;
|
|
Flds = iConf->Fields;
|
|
//
|
|
// Send the message using the network. (SMTP protocol over the network)
|
|
//
|
|
Flds->Item[cdoSendUsingMethod]->Value = _variant_t((long)cdoSendUsingPort);
|
|
//
|
|
// Define SMTP server
|
|
//
|
|
Flds->Item[cdoSMTPServer]->Value = _variant_t(lpctstrServer);
|
|
//
|
|
// Define SMTP port
|
|
//
|
|
Flds->Item[cdoSMTPServerPort]->Value = _variant_t((long)dwPort);
|
|
//
|
|
// Define SMTP connection timeout (in seconds)
|
|
//
|
|
Flds->Item[cdoSMTPConnectionTimeout]->Value = _variant_t(SMTP_CONN_TIMEOUT);
|
|
//
|
|
// Make sure we don't used cached info for attachments
|
|
//
|
|
Flds->Item[cdoURLGetLatestVersion]->Value = _variant_t(VARIANT_TRUE);
|
|
//
|
|
// Choose authentication method
|
|
//
|
|
switch (AuthType)
|
|
{
|
|
case CDO_AUTH_ANONYMOUS:
|
|
Flds->Item[cdoSMTPAuthenticate]->Value = _variant_t((long)cdoAnonymous);
|
|
break;
|
|
|
|
case CDO_AUTH_BASIC:
|
|
Flds->Item[cdoSMTPAuthenticate]->Value = _variant_t((long)cdoBasic);
|
|
Flds->Item[cdoSendUserName]->Value = _variant_t(lpctstrUser);
|
|
Flds->Item[cdoSendPassword]->Value = _variant_t(lpctstrPassword);
|
|
break;
|
|
|
|
case CDO_AUTH_NTLM:
|
|
//
|
|
// NTLM authentication required the calling client (that's us)
|
|
// to impersonate the user
|
|
//
|
|
Flds->Item[cdoSMTPAuthenticate]->Value = _variant_t((long)cdoNTLM);
|
|
break;
|
|
|
|
default:
|
|
ASSERT_FALSE;
|
|
}
|
|
//
|
|
// Update configuration from the fields
|
|
//
|
|
Flds->Update();
|
|
//
|
|
// Store configuration in the message
|
|
//
|
|
iMsg->Configuration = iConf;
|
|
//
|
|
// Set recipient
|
|
//
|
|
iMsg->To = lpctstrTo;
|
|
//
|
|
// Set sender
|
|
//
|
|
iMsg->From = lpctstrFrom;
|
|
//
|
|
// Set subject
|
|
//
|
|
iMsg->Subject = lpctstrSubject;
|
|
//
|
|
// Set message format to MIME
|
|
//
|
|
iMsg->MimeFormatted = _variant_t(VARIANT_TRUE);
|
|
//
|
|
// Set charset to Unicode (UTF-8)
|
|
//
|
|
iMsg->BodyPart->Charset = "utf-8";
|
|
iMsg->BodyPart->ContentTransferEncoding = "base64";
|
|
|
|
IBodyPartPtr iBp;
|
|
//
|
|
// Get message body root
|
|
//
|
|
iBp = iMsg;
|
|
//
|
|
// Set content type fo mixed to support both body and attachment
|
|
//
|
|
iBp->ContentMediaType = "multipart/mixed; charset=""utf-8""";
|
|
|
|
if (lpctstrBody)
|
|
{
|
|
//
|
|
// Add body text
|
|
//
|
|
IBodyPartPtr iBp2;
|
|
_StreamPtr Stm;
|
|
//
|
|
// Add text body under root
|
|
//
|
|
iBp2 = iBp->AddBodyPart(-1);
|
|
//
|
|
// Use text format
|
|
//
|
|
iBp2->ContentMediaType = "text/plain";
|
|
//
|
|
// Set charset to Unicode (UTF-8)
|
|
//
|
|
iBp2->Charset = "utf-8";
|
|
iBp2->ContentTransferEncoding = "base64";
|
|
//
|
|
// Get body text stream
|
|
//
|
|
Stm = iBp2->GetDecodedContentStream();
|
|
//
|
|
// Write stream text
|
|
//
|
|
Stm->WriteText(lpctstrBody, adWriteChar);
|
|
Stm->Flush();
|
|
|
|
|
|
}
|
|
if (lpctstrHTMLBody)
|
|
{
|
|
//
|
|
// Set content type to alternative to support both plain text body and HTML body
|
|
// If an attachment is added afterwards, the ContentMediaType is automatically set
|
|
// to mixed and the multipart/alternative is moved to new sub-BodyPart.
|
|
//
|
|
iBp->ContentMediaType = "multipart/alternative; charset=""utf-8""";
|
|
|
|
IBodyPartPtr iBp2;
|
|
_StreamPtr Stm;
|
|
|
|
//
|
|
// Add html body under root
|
|
//
|
|
iBp2 = iBp->AddBodyPart(-1);
|
|
//
|
|
// Use html format
|
|
//
|
|
iBp2->ContentMediaType = "text/html";
|
|
//
|
|
// Set charset to Unicode (UTF-8)
|
|
//
|
|
iBp2->Charset = "utf-8";
|
|
iBp2->ContentTransferEncoding = "base64";
|
|
//
|
|
// Get body html stream
|
|
//
|
|
Stm = iBp2->GetDecodedContentStream();
|
|
//
|
|
// Write stream html
|
|
//
|
|
Stm->WriteText(lpctstrHTMLBody, adWriteChar);
|
|
Stm->Flush();
|
|
|
|
}
|
|
if (lpctstrAttachmentPath)
|
|
{
|
|
//
|
|
// Add attachment
|
|
//
|
|
IBodyPartPtr iBpAttachment;
|
|
iBpAttachment = iMsg->AddAttachment(lpctstrAttachmentPath, TEXT(""), TEXT(""));
|
|
iBpAttachment->ContentMediaType = "image/tif";
|
|
|
|
if (lpctstrHTMLBody)
|
|
{ // The multipart/alternative section was moved to sub-bodypart and
|
|
// the main ContentMediaType was moved with it so now we restore it.
|
|
iBp->ContentMediaType = "multipart/mixed; charset=""utf-8""";
|
|
}
|
|
|
|
if (lpctstrAttachmentMailFileName)
|
|
{
|
|
//
|
|
// User wishes to rename attachment in the mail message
|
|
//
|
|
FieldsPtr Flds = iBpAttachment->Fields;
|
|
_bstr_t bstrContentType = iBpAttachment->ContentMediaType +
|
|
TEXT("; name=\"") +
|
|
lpctstrAttachmentMailFileName +
|
|
TEXT("\"");
|
|
Flds->Item[cdoContentType]->Value = _variant_t(bstrContentType);
|
|
Flds->Update();
|
|
Flds->Resync(adResyncAllValues);
|
|
}
|
|
}
|
|
if (CDO_AUTH_NTLM == AuthType)
|
|
{
|
|
//
|
|
// We impersonate the user in the NTLM authentication mode.
|
|
// This is the last thing we do just before sending the message.
|
|
//
|
|
Assert (hLoggedOnUserToken);
|
|
|
|
if (!ImpersonateLoggedOnUser (hLoggedOnUserToken))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("ImpersonateLoggedOnUser failed. (hr: 0x%08x)"),
|
|
hr);
|
|
goto exit;
|
|
}
|
|
|
|
bImpersonated = TRUE;
|
|
}
|
|
//
|
|
// Finally - send the message
|
|
//
|
|
iMsg->Send();
|
|
}
|
|
catch (_com_error &er)
|
|
{
|
|
//
|
|
// Error in CDO2
|
|
//
|
|
hr = er.Error ();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("CDO2 Error 0x%08x: to:%s, subject:%s")
|
|
#ifdef UNICODE
|
|
TEXT(" Description:%s")
|
|
#endif
|
|
,hr,
|
|
lpctstrTo,
|
|
lpctstrSubject
|
|
#ifdef UNICODE
|
|
,(LPCTSTR)er.Description()
|
|
#endif
|
|
);
|
|
}
|
|
|
|
exit:
|
|
CoUninitialize();
|
|
if (bImpersonated)
|
|
{
|
|
if (!RevertToSelf ())
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("RevertToSelf failed. (hr: 0x%08x)"),
|
|
hr);
|
|
}
|
|
}
|
|
return hr;
|
|
} // SendMail
|
|
|