CMapi v1.36
Welcome to CMapi, a set of C++ classes to encapsulate sending and
receiving mail using Simple MAPI.
Simple MAPI is a set of functions exported by MAPI32.dll which allows you to
send and receive mail in a transport independent way. It is an optional part of
all Win32 operating systems since Windows 95. MAPI is intended
more for the corporate environment when compared with the Internet mail standard
SMTP e.g. products such as MS Exchange Server use MAPI extensively. Transport providers
are available for a number of messaging transports including Exchange Server, SMTP,
Fax etc. To be able to specify different transports, MAPI provides
the concept of profiles which are setup using the Mail control panel applet.
Features
- Simple and clean C++ interface.
- As of v1.33, CMapi now includes support for sending Unicode formatted
messages.
- The code can be used in a console application or without bringing up any
interactive dialogs if so desired.
- The code gracefully handles the case where MAPI is not installed on client
machines. Internally the class loads the MAPI DLL itself and uses GetProcAddress
API calls.
Copyright
- You are allowed to include the source code in any product (commercial,
shareware, freeware or otherwise) when your product is released in binary
form.
- You are allowed to modify the source code in any way you want except you
cannot modify the copyright details at the top of each module.
- If you want to distribute source code with your application, then you
are only allowed to distribute versions released by the author. This is to
maintain a single distribution point for the source code.
Usage
- The classes are designed for VC 2017 or later. They will not compile on
earlier releases of VC.
- To use the class in your code simply include CMapi.cpp in your project and
#include CMapi.h in which ever of your modules needs to make calls to the classes.
- The code can operate with or without MFC.
History
v1.36 (23 September 2023)
- Updated SAL across the code.
v1.35 (11 May 2023)
- Updated copyright details
- Updated modules to indicate that it needs to be compiled using
/std:c++17. Thanks to Martin Richter for reporting this issue.
v1.34 (19 March 2022)
- Updated copyright details.
- Updated the code to use C++ uniform initialization for all variable
declarations.
- Updated the code to use std::[w]string::data method throughout. This
means that the code must now be compiled using /std:c++17.
v1.33 (4 May 2020)
- Fixed more Clang-Tidy static code analysis warnings in the code.
- Added support for MapiSendMailW. This allows the code to support Unicode
formatted emails.
v1.32 (19 March 2020)
- Updated copyright details.
- Fixed more Clang-Tidy static code analysis warnings in the code.
v1.31 (29 December 2019)
- Fixed various Clang-Tidy static code analysis warnings in the code.
v1.30 (11 September 2019)
- Fixed a number of compiler warnings when the code is compiled with VS
2019 Preview
v1.29 (22 April 2019)
- Updated copyright details
- Updated the code to clean compile on VC 2019
v1.28 (14 October 2018)
- Reimplemented the CMapi::CMessage::AddMultipleAttachments method.
- Renamed the the CMapi::CMessage::ParseMultipleRecipients method to
AddMultipleRecipients. In addition this method no longer clears the
recipients vector at the start of the method.
v1.27 (11 October 2018)
- Updated copyright details.
- Fixed a number of C++ core guidelines compiler warnings. These changes
mean that the code will now only compile on VC 2017 or later.
- Removed all code which supported CMAPI_MFC_EXTENSIONS code path
- Replaced BOOL with bool throughout the code
v1.26 (24 November 2015)
- Updated code to clean compile on VC 2015
v1.25 (22 March 2015)
- Updated code to clean compile on VC 2013
- Updated copyright details.
- All CWnd* parameters have been replaced with HWND parameters.
- The classes have now been put in a CMapi namespace and have been renamed
to CRecipient, CMessage & CSession
- Reworked the classes to optionally compile without MFC. By default
the classes now use STL classes and idioms but if you define
CMAPI_MFC_EXTENSIONS the classes will revert back to the MFC behaviour.
- Reworked all the classes so that all the exposed strings are now
ASCII. The onus is now on client code to convert the data to ASCII when
integrating with the CMapi classes.
v1.24 (4 October 2012)
- Updated copyright details
- Updated code to clean compile on VC 2012
- Code no longer uses SearchPath or LoadLibrary without an absolute path
when loading MAPI DLL. This avoids DLL planting security issues.
v1.23 (1 April 2011)
- Updated copyright details.
- Replaced use of CT2A with CStringA
- Updated sample app to clean compile on VC 2010
v1.22 (6 November 2008)
- Updated the zip file to remove the now defunct PJNConv.h header file
- The sample app now uses DPAPI to encrypt the profile & password
configuration settings
v1.21 (16 September 2008)
- Updated copyright details.
- Code now compiles cleanly using Code Analysis (/analyze)
- Updated code to compile correctly using _ATL_CSTRING_EXPLICIT_CONSTRUCTORS
define
- Updated sample app to clean compile on VC 2008
- The code has now been updated to support VC 2005 or later only.
- Removed VC 6 style AppWizard comments from the code.
- Renamed CMapiMessage::AddMultipleAttachements to
CMapiMessage::ParseMultipleRecipients and reworked its parameters to be in
line with the author's SMTP class.
- Reworked the way the code handles allocations for the ASCII strings
required by simple MAPI. Now these are allocated in the message itself
rather than using raw heap allocations via the old H_T2A macro
- AddMultipleRecipients has been renamed to ParseMultipleRecipients in
line with the author's SMTP class
- The CMapiRecipient constructor which takes one string parameter now
supports breaking the address into email address and friendly name parts
- AddMultipleAttachments now returns the number of attachments added
v1.20 (1 January 2007)
- Updated copyright details.
- Fixed incorrect usage of preprocessor macro in
CMapiMessage::AddMultipleRecipients method
v1.19 (22 December 2006)
- Further updates to fix compile issues for the sample app on VC 2005
- Subject and body and email messages are now allocated using the H_T2A
macro. This will avoid problems with large CString values for these fields
- Fixed a bug in CMapiSession::Logoff where the return value would always
be TRUE
- A empty profile name is now allowed in the sample app.
- Configuration dialog is now not shown unnecessarily when you send an
email in the sample app.
- Logon is now only attempted in the sample app if the Interactive flag is
not set
- Addition of a CMAPI_EXT_CLASS preprocessor macro to allow the classes to
be more easily added to an extension dll
v1.18 (26 July 2006)
- Minor update to Logoff to avoid 2 asserts which occur when MAPI is not
installed on client machines. Thanks to Sergiu Scobici for reporting this
v1.17 (23 July 2006)
- Updated copyright details.
- Optimized CMapiMessage constructor code.
- Optimized CMapiSession constructor code.
- Code now uses newer C++ style casts instead of C style casts.
- Updated documentation to use the same style as the web site.
- Fixed a bug freeing up strings in the sample app's
CEnumMessagesDlg::OnDestroy method
- Updated the code to clean compile on VC 2005
- Sample app now allows you to specify no To address if the interactive
setting is specified
- Removed an unnecessary assert from CMapiMessage::AddMultipleRecipients
and CMapiMessage::AddMultipleAttachements.
- Updated some assert logic in CMapiSession::Send to not assert on the
recipient count if we are sending a message "Interactive". Thanks to Sergiu
Scobici for reporting this issue.
- Refactored some code in CMapiSession::Send into
CMapiSession::SetupRecipients. Again thanks to Sergiu Scobici for reporting
this
v1.16 (19 August 2005)
- Fixed a bug in the calculation of the flags parameter in the call to acquire
a shared logon in the Logon method. Thanks to Albert van Peppen for reporting
this problem.
v1.15 (14 August 2005)
- Fixed problems when the code is compiled for UNICODE. The issue was that
the Send method was using the various T2A macros which uses a stack based string.
This was causing issues because the recipients and attachments array for the
MAPI message was being allocated in loops which was using scoping. This scoping
was causing the stack based strings to be deallocated before the "MAPISendMail"
method was called. This issue has now been fixed by the introduction of new
generic heap based macros in PJNConv.h which allocates the converted string
using the C++ new operator. To ensure orderly cleanup of this heap memory, the
MapiMessage structure is now allocated using a hidden C++ class "CMapiMessageCleanup"
which cleans up this memory automatically in its destructor. These macros are
quite generic and can be used independent of the CMapi class in places where
your code has the handle this exact same issue.
v1.14 (13 August 2005)
- Fixed a number of bugs related to the use of MAPI_FORCE_DOWNLOAD setting.
Thanks to Albert van Peppen for this.
- Optimized AddMultipleReceipients and AddMulipleAttachments function somewhat
by using new CString::Trim method when available as well as avoiding addresses
which are empty. Again thanks to Albert van Peppen for this.
- MAPI_FORCE_DOWNLOAD is now set if Logon method has to attempt a shared logon.
Again thanks to Albert van Peppen for this.
- Fixed a bug in SharedLogon where the MAPI_FORCE_DOWNLOAD flag was not being
passed. Again thanks to Albert van Peppen for this.
- Replaced calls to ZeroMemory with memset.
- Class now supports sending HTML emails (well kindof!). To achieve this a
new parameter "bSendAsHTML" is included in the Send method. Please note that
the HTML is sent as an additional attachment before all the other attachments
and its disposition type is still marked as an attachment (at least using the
latest version of Outlook on Windows XP). In addition some mail clients (such
as Outlook Express) will still interpret this as an attachment as opposed to
inline. If you are not happy with this then you will need to look into using
Extended MAPI which this class does not provide for (and will never) or better
yet, you should use SMTP directly, since HTML email is really part of the SMTP
suite of protocols. For example you could use the author's own CPJNSMTPConnection
class. Again thanks to to Albert van Peppen for this.
- Sample app now allows multiple attachments to be specified as edit box is
now not read only.
- Fixed a duplicate mneumonics issue in the main dialog in the sample app
- File dialog which appears in the sample app when you add an attachment not
includes a standard file name filter.
- Fixed a number of compiler warnings when the code is compiled using the
new Force conformance in for loop setting in Visual Studio 2003.
- Fixed a number of compiler warnings when the code is compiled using the
Detect 64-bit portability issues in Visual Studio 2003. Please note that this
means the codes requires a recentish copy of the Platform SDK to be installed
if you are compiling the code on Visual C++ 6.0
v1.13 (30 April 2005)
- Fix for a bug where the MapiMessage::flFlags value was not being set when
a message was being sent. Failure to set the flags value meant that CMapi did
not support the "MAPI_RECEIPT_REQEUSTED" flag. Thanks to Marcel Scherpenisse
for reporting this bug.
v1.12 (5 June 2004)
- Added a parameter to the Logon methods to allow emails to be download (i.e.
MAPI_FORCE_DOWNLOAD). Thanks to "caowen" for this update.
v1.11 (5 May 2004)
- Added support for deleting emails via MAPI. Thanks to Marcel Scherpenisse
for this addition.
- Also added the helper function CMapiMessage::AddMultipleAttachments. Again
thanks to Marcel Scherpenisse for this addition.
22 February 2004
- Updated the sample app to ensure the password was passed as a parameter
when calling CMapi::Logon. Thanks to "Alan" for pointing this out.
v1.10 (5 February 2004)
- Added a pragma message to inform uses about including afxtempl.h in the
precompiled header to avoid compiler errors.
v1.09 (22 December 2003)
- Added support for reading mail thro MAPI. Thanks to Marcel Scherpenisse
for this addition.
v1.08 (5 July 2003)
- Fixed a bug in the ordering of the string parameters to the CMapiRecipient
constructor. Thanks to "Louchkov" for spotting this problem.
v1.07 (25 January 2003)
- Updated copyright messages.
- Made CMapiSession destructor virtual.
- Made a new CMapiRecipient class. This allows finer control over setting
the display name and the address individually. Thanks to the people on the discussion
board on codeproject.com for reporting this problem. The problem arose when
Outlook Express displays its security dialog about an unattended mapi mail being
sent. In this dialog the "To" fields were all empty. It seems that OE only displays
the addresses in this dialog. Perhaps because so many viruses abound the address
is more relevant that the actual friendly name.
2 October 2002
- Updated the caption in the configuration dialog in the sample app when asking
for configuration settings
- Updated the sample app to not ask for configuration if you are trying to
send using a shared MAPI session.
v1.06 (18 July 2000)
- Fixed check for MAPI being installed when client apps create an incorrect
"MAPI" entry in win.ini or the registry, Thanks to Chris Raethke for spotting
this.
- A "SharedLogon" method has been provided which tries to acquire a shared
MAPI session
- SendMessage method has been extended to allow the message to be interactively
edited.
v1.05 (22 June 2000)
- Fixed a bug in CMapiMessage::AddMultipleRecipients where BCC recipients
were not being added correctly.
v1.04 (21 May 2000)
- Added an optional parameter to CMapi::SendMessage to allow you to decide
whether or not addresses should be resolved.
v1.03 (2 April 2000)
- Password field in the configuration dialog now uses ES_PASSWORD edit control
style.
- Password value used for MAPI logon is now stored in the registry encrypted
instead of as plain text.
v1.02 (28 March 2000)
- Provision of a sample app which implements a mini mail sender.
- Added a CMapiMessage::AddMultipleRecipients method similar to my SMTP class.
v1.01 (5 December 1999)
- Fixed potential problem where CMapi is used in a console app which was giving
an ASSERT
- Fixed an assert which can occur if you dismiss the login dialog when doing
an interactive MAPI logon
v1.0 (14 May 1999)
API Reference
The API consists of the following 2 classes in the namespace CMapi and their methods and variables:
CMessage
CMessage::m_To
CMessage::m_CC
CMessage::m_BCC
CMessage::m_sSubject
CMessage::m_sBody
CMessage::m_Attachments
CMessage::m_AttachmentTitles
CMessage::m_From
CMessage::m_sDateReceived
CMessage::m_sMessageType
CMessage::m_Flags
CSession
CSession::CSession
CSession::~CSession
CSession::Logon
CSession::SharedLogon
CSession::LoggedOn
CSession::Logoff
CSession::Send
CSession::Find
CSession::Read
CSession::Delete
CSession::MapiInstalled
CSession::GetLastError
CMessage::m_To
Remarks
m_To is of type std::vector<CRecipient> and contains the array
of recipients which the email is to be mailed to. The name of each recipient can
be a friendly name (the friendly name is the name which a recipient with an address
book entry is known as e.g. "Joe at Work" could map to using an SMTP MAPI
transport to send to joe@somecompany.com) or it can be a specific transport
address e.g. SMTP:joe@somecompany.com, FAX:34567 etc.
CMessage::m_CC
Remarks
m_CC is of type std::vector<CRecipient> and contains the array
of recipients which the email will be Carbon Copied to. The way addresses
are specified is the same as for m_To.
CMessage::m_BCC
Remarks
m_BCC is of type std::vector<CRecipient> and contains the array
of recipients which the email will be Blind Carbon Copied to. The way
addresses are specified is the same as for m_To.
CMessage::m_sSubject
Remarks
m_sSubject is of type std::string and is the subject line of the email.
CMessage::m_sBody
Remarks
m_sBody is of type std::string and is the body of the email.
CMessage::m_Attachments
Remarks
m_Attachments is of type std::vector<std::string> and is a list of filenames to be included
as attachments in the email.
CMessage::m_AttachmentTitles
Remarks
m_AttachmentTitles is of type std::vector<std::string> and contains the titles of what
each file attachment will be known as to recipients of this message. If you
leave this array empty then the title will be the same as the filename.
CMessage::m_From
Remarks
The originator of this email. This is only filled in when the message is returned
from the Read function.
CMessage::m_sDateReceived
Remarks
A string version of when the emailed was received. This is only filled in when
the message is returned from the Read function.
CMessage::m_sMessageType
Remarks
The MAPI message type. This is only filled in when the message is returned from
the Read function. Corresponds to the MapiMessage::lpszMessageType variable
CMessage::m_Flags
Remarks
The MAPI flags for this message. This is only filled in when the message is returned
from the Read function. Corresponds to the MapiMessage::flFlags variable
CSession::CSession
CSession();
Remarks
Standard constructor for the class. This class is the main MAPI support class
and contains the functions to actually send the mail message.
CSession::~CSession
virtual ~CSession();
Remarks
Standard destructor for the class. Internally this logs you out of MAPI if you're
logged in and unloads the MAPI dll.
CSession::Logon
bool Logon(const std::string&
sProfileName, const std::string&
sPassword = _T(""), HWND hParentWnd =
nullptr, bool
bForceDownload = false);
Return Value
true if you were successfully logged in to MAPI otherwise FALSE
Parameters
sProfileName MAPI profile name to use to logon.
sPassword Password associated with the profile (if any).
hParentWnd The parent window indicating that if a dialog box is displayed,
it is modal with respect to.
bForceDownload true if you want messages to be downloaded before the function
returns.
Remarks
Logons to the MAPI messaging system creating a session with it. If you pass an
empty profile name then Logon will try to interactively logon by presenting the
normal MAPI logon dialog. Specifying nullptr as the parent window as is the default
will use the window as returned by AfxGetMainWnd(). Please note that you must be
logged on to MAPI prior to sending a message. Internally the code will "ASSERT"
to ensure you do not forget to do this.
CSession::SharedLogon
bool Logon(bool bForceDownload
= false);
Return Value
true if you were successfully logged in to MAPI otherwise false
Parameters
bForceDownload true if you want messages to downloaded before the function
returns.
Remarks
Logons to the MAPI messaging system by using a "shared" MAPI session. i.e. it
will try to use an existing mapi session and if there is none, then this function
will fail. For further info on "shared" MAPI sessions, please check the MSDN.
CSession::LoggedOn
bool LoggedOn() const;
Remarks
Simply accessor which returns true if this instance is logged on to MAPI otherwise
false.
CSession::Logoff
bool Logon();
Return Value
true if you were successfully logged off from MAPI otherwise false
Remarks
The corollary function to Logon. Internally this function is called in the
CSession
destructor.
CSession::Send
bool Send(CMessage& message, bool bResolve
= false, bool bInteractive = false, HWND
hParentWnd = nullptr, bool bSendAsHTML
= false);
Return Value
true if the message was successfully sent otherwise false.
Parameters
message Message to be sent
bResolve true if the recipient addresses should be resolved otherwise false.
bInteractive true if you want the message to be editable by the end user
prior to the message actually being sent.
hParentWnd If bInteractive is true, then this is the parent window to
use.
bSendAsHTML Should the body of the email be sent as HTML as opposed to
plain text. For more information on this option, please read the release notes for
v1.14
Remarks
Sends the message as specified in the "message" parameter, using the MAPI profile
currently logged into. If you set bResolve to true, then the recipient's address
will be looked up in the profiles address books, prior to sending. This can lead
to the following problem: if two people have identical "resolved" names but different
e-mail addresses, the CMapi class is unable to send mail to either address because
after the address is resolved, the recipient becomes "ambiguous," and MAPISendMail
returns the MAPI_E_AMBIGUOUS_RECIPIENT (21) error code. Normally you should accept
the default of not to resolve addresses.
CSession::Find
bool Find(std::string& sMessageID, const std::string& sSeedMessageID
= _T(""), FLAGS flFlags = MAPI_LONG_MSGID,
const std::string& sMessageType = _T(""),
bool
bInteractive = false, HWND hParentWnd
= nullptr);
Return Value
true if the message was successfully found otherwise false.
Parameters
sMessageID Upon return, this contains the message ID of the found email.
sSeedMessageID The ID of the message to "seed" the search with.
flFlags The flags to use in the call to MAPIFindNext.
sMessageType The type of message to search for.
bInteractive true if you want any UI to be displayed as part of the search.
hParentWnd If bInteractive is true, then this is the parent window to
use.
Remarks
Searches for the specified message. For details on how you search for messages,
check out the code in "EnumMessagesDlg.cpp" in the sample app.
CSession::Read
bool Read(const std:string& sMessageID, CMessage&
message, FLAGS flFlags = MAPI_SUPPRESS_ATTACH,
bool bInteractive = false, HWND
hParentWnd = nullptr);
Return Value
true if the message was successfully found otherwise false.
Parameters
sMessageID The message ID of the email to read.
message Upon successful return this contains the read message.
flFlags The flags to use in the call to MAPIReadMail.
bInteractive true if you want any UI to be displayed as part of the read.
hParentWnd If bInteractive is true, then this is the parent window to
use. If it is left as nullptr, then the window as returned by AfxGetMainWnd() will
be used.
Remarks
Reads the specified message. For details on how you read messages, check out
the code in "EnumMessagesDlg.cpp" in the sample app.
CSession::Delete
bool Delete(std::string& sMessageID, bool bInteractive
= false, HWND hParentWnd = nullptr);
Return Value
true if the message was successfully deleted otherwise false.
Parameters
sMessageID Upon return, this contains the message ID of the found email.
bInteractive true if you want any UI to be displayed as part of the deletion.
hParentWnd If bInteractive is true, then this is the parent window to
use. If it is left as nullptr, then the window as returned by AfxGetMainWnd() will
be used.
Remarks
Deletes the specified message.
CSession::MapiInstalled
bool MapiInstalled() const;
Remarks
Simply accessor which returns true if MAPI is installed and has been correctly
initialized ready for this instance to use. The actual loading of the MAPI dll is
handled internally by the CSession constructor, meaning it is valid this function
anytime after you have constructed a CSession instance.
CSession::GetLastError
DWORD GetLastError() const;
Return Value
The last MAPI error generated by this CSession instance.
Remarks
Since the class uses MAPI which has its own way of reporting errors different
to the standard Win32 way (GetLastError), this method allows this value to be retrieved.
MAPI errors are documented in the MAPI.h file in your VC include directory.
Contacting the Author
PJ Naughter
Email: pjna@naughter.com
Web: http://www.naughter.com
23 September 2023