Introduction
" MAPI
is a set of functions
that mail-enabled and mail-aware applications use to create, manipulate,
transfer, and store mail messages. It gives application developers the
tools to define the purpose and content of mail messages, and gives them
flexibility in their management of stored mail messages. MAPI
also
provides a common interface that application developers can use to create
mail-enabled and mail-aware applications independent of the underlying
messaging system. " --- Quoted from MSDN.
I am not an expert on either MAPI or e-mail
in general. I found that using MAPI
functions is not exactly easy. What I need is a simple reusable component
that provides simple e-mail functionality to all of my programs on the Win32 platforms. For example, when a
serious error occurs in my system, I want an e-mail message to be sent
to a list administrators, I also want the same to be done when our servers
are about to run out of virtual memory. Some of my server programs
also have to process e-mails (read messages from the inbox and call various
services accordingly).
But I was too lazy to sit down and learn all the MAPI
functions. Fortunately, there is an ActiveX control MSMAPI32.ocx
from Microsoft, which comes with VC++ and other MS products. I don't
really like the way this control works, and most importantly I want to
make things easier, so I wrote a com component XYMail.dll
which uses this control to provide simple e-mail functionality. You can use and modify the source code anyway you wish, but give me some credit if possible (please? :-).
XYMailClient
XYMailClient is a com object implemented in XYMail.dll. It provides the following
thread-safe methods:
BOOL InitSession(BSTR
strProfile, BSTR strPassword);
This method is called to establish a MAPI session
with the mail server. The strProfile
parameter is the name of an e-mail profile for the current user, and strPassword
is the password (use empty string if there is no password). The established
session is global to the process. That is, the established session
is available to all the other XYMailClient
objects in the same process until the EndSession
method is called. The return value indicates whether the operation
is successful. In case of error, a trace message will be written
to the XYMail.log file in the current working
directory.
BOOL SendMsg(BSTR
strTo, BSTR strCc, BSTR strBcc, BSTR strTitle, BSTR strText, BSTR strAttachment);
Call this method to send an e-mail message to the recipients specified
by the arguments. The strTo,
strCc, and strBcc
are all lists of semi-colon delimited e-mail addresses. The strTitle
parameter is the message subject, and strText
is the message body. The strAttachment
parameter is a semi-colon delimited list of full path names for attachment
files. The return value indicates whether the operation is successful.
In case of error, a trace message will be written to the XYMail.log
file in the current working directory.
long FetchMsg();
Call this method to fetch all in-coming messages from the mail server.
The return value is the total number of messages in the inbox. In
case of error, the return value will be -1
and a trace message will be written to the XYMail.log
file in the current working directory.
BSTR GetMsg(long nIndex);
Call this method to retrieve the message in the inbox with the given
(zero-based) index. The returned value is a string of the following
format:
<XYMail><Sender>...</Sender><Title>...</Title><Text>...</Text><br>
<Attachment>...</Attachment><Received>...</Received></XYMail>
The fields within this string packet can be extracted using the ExtractValue
method. If there is no such message, the return value will be the
empty string and a trace message will be written to the XYMail.log
file in the current working directory.
void DeleteMsg(long nIndex);
Call this method to delete the message from the inbox with the given
(zero-based) index. If nIndex
is -1, then all messages will
be deleted. Note that if you want to delete multiple messages using this method, you need to go from higher index to lower index because deleting a message with lower index first will change indices of remaining messages.
BSTR ExtractValue(BSTR
strField, BSTR strDataPacket);
Call this method to extract a message field from the input string packet.
The strDataPacket parameter
is the return value of a previous call to the GetMsg
method and strField can be
one of the following strings: "Sender", "Title",
"Text", "Attachment", "Received".
void EndSession();
Call this method to terminate the current MAPI
session. Note that the MAPI session
is global to the process and this method affects all XYMailClient objects within the same process.
Sample code
Here is a complete C++ console application that demonstrates the e-mail
functions using
XYMailClient. The header
file XYMailClientWrapper.h is included with
the source code, it declares a wrapper class for
XYMailClient.
#include "XYMailClientWrapper.h"
#include <stdio.h>
void main()
{
XYMailClientWrapper xyMail;
xyMail.InitSession("MyProfileName","");
xyMail.SendMsg("guy@aol.com;girl@aol.com","ok@aol.com","<a href="mailto:hey@aol.com">hey@aol.com</a>",
"Test","A test","<a href="file:
Here is a VB script file that does almost exactly the same things as
the above C++ program:
dim obj
set obj = CreateObject("XYMailClient.1")
obj.InitSession("MyProfileName", "")
obj.SendMsg("guy@aol.com;girl@aol.com","ok@aol.com","<a href="mailto:hey@aol.com">hey@aol.com</a>",
"Test","A test","c:\\test1.txt;c:\\test2.txt"));
WScript.echo obj.FetchMsg()
dim strMsg
strMsg = obj.GetMsg(0)
WScript.echo obj.ExtractValue("Sender", strMsg)
WScript.echo obj.ExtractValue("Title", strMsg)
WScript.echo obj.ExtractValue("Text", strMsg)
WScript.echo obj.ExtractValue("Attachment", strMsg)
WScript.echo obj.ExtractValue("Received", strMsg)
obj.DeleteMsg(1)
obj.DeleteMsg(0)
obj.DeleteMsg(-1)
obj.EndSession()
set obj = Nothing
Using XYMailClient in your own program
XYMailClient is implemented with VC++ 5.0
using ATL and MFC. In case you are interested in implementation details,
you need only to read one source file XYMailClient.cpp,
all the other files in the project are generated by the AppWizard.
To install XYMailClient, you need to copy XYMail.dll onto your machine and register
it. However, XYMailClient depends on MSMAPI32.ocx so you need to install that,
too (most machines already have it). You also have to configure an
e-mail profile before using XYMailClient.
You can use the Mail icon in the control panel
to configure it (you already did this if MS Outlook
is currently working on your machine).
For your convenience, I have included a header file XYMailClientWrapper.h,
which contains a C++ wrapper class. To use XYMailClient
in a C++ program, you need only to do the following: include this header
file, declare a XYMailClientWrapper object,
and call its methods. A known problem on using XYMailClient
in a C++ console application is that you must call the EndSession
method before terminating your program, otherwise your program will crash.
If you try to use XYMailClient within an
NT service or within a process created by an NT service, you may not be
able to call InitSession
successfully. This is because the NT service may be running under
the default system account, which has no e-mail profile. You can
configure an NT service to run under a regular user account so that an
e-mail profile is available. This will solve the problem in most
cases.
Thank you for reading this article. Please visit my home
page for my other articles and programs.
History
12 Mar 2002 - updated source
6 Nov 2002 - updated source