Using the Microsoft Mail API

Encapsulating message information

Jim Conger

Jim is a business manager for Chevron Chemical and the author of numerous programming books, including the recently published Windows API New Testament (The Waite Group, 1994). Jim can be contacted on CompuServe at 73220,324.


Electronic mail has become a mainstream application. For many of us, the electronic-mail system is the primary application we use every day, with word processors and spreadsheets filling lesser roles. For the most part, e-mail systems have been used to simply send and receive text messages which would otherwise have been sent on a printed page. Many developers, however, have discovered that e-mail is capable of doing much more than simply transmitting text. Lotus Notes has popularized the concept of a textual database, which allows groups to collect and organize more-structured documents. The integration of OLE into several mail systems has made file transfer simple enough for most users to master with very limited training. A logical extension to e-mail is to build custom applications that mirror a company's existing work procedures. This can vary from simple input forms, to complex applications that lead the user through a complete work process. Figure 1 is the main window of an application which structures requests for technical information. This application can be run from within Microsoft Mail or as a stand-alone program. In the latter case, the application starts a background mail session to transmit the data as a specially identified MS Mail message. The application also "pops up" whenever an incoming message of this type is selected from within the MS Mail in-box.

Microsoft Mail Extensions

There are two keys to extending MS Mail beyond simple messaging. The first is the MAPI.DLL library, which exports 12 functions that you can call within your own program. Microsoft calls this the "simple mail API" since it intends to add to the function list in future releases of Mail. Table 1 is a list of the MAPI functions, which are documented in the Microsoft Mail Technical Reference and the Microsoft Development Library (MSDN) CD-ROM. You can call these functions within Access, Excel, Word Basic, Visual Basic, or just about any other development platform. The MAPI functions are easy to use, and provide a lot of horsepower for a minimum effort.

The second key to extending MS Mail is Microsoft's APPEXEC.DLL, which passes information about a message received by MS Mail to another application. The information is transferred by passing the handle of a global-memory block containing a message identifier. The handle is passed using a clever trick that I have not seen elsewhere. If APPEXEC.DLL is called with a command line containing the string <PARAMBLK>, that string is replaced in the command-line arguments with the hexadecimal handle of the global-memory block containing the message information. In other words, if APPEXEC.DLL is called with the command-line arguments APPEXEC.DLL <PARAMBLK>, the DLL will overwrite the <PARAMBLK> string with a handle to APPEXEC.DLL B046. The program wishing to read the message can then use this handle to read the memory block. Example 1 shows how the memory block is accessed. The application takes ownership of the memory block by calling GlobalRealloc() using the GMEM_ MODIFY| GMEM_MOVEABLE|GMEM_SHARE flags, and then works directly with the data in memory.

The memory block will contain information about the message (or messages) that the user has selected from within MSMAIL.EXE. The data is organized as a PARAMBLK structure; see Example 2. The key member of this structure is lpMessageIDList, which contains one or more unique message identifiers. The message identifier is used to read the actual message data using MAPIReadMail().

The combination of the mail functions in MAPI.DLL and the APPEXEC.DLL library gives you the flexibility to build your own application right into the fabric of MS Mail. Figure 2 is a conceptual model of how these tools work together.

Custom Message Types

Mail supports the concept of different message types. Normal text messages are the default type, but you can create your own specialized message types to handle transmittal of more-structured data. The message identifier allows Mail to route specific types of messages to different applications, instead of always displaying the message data as text. Mail (MSMAIL.EXE) is made aware of the specialized message types by adding an entry to the MSMAIL.INI file in the user's Windows subdirectory. Example 3 is a typical entry that creates a custom message type "MailDemo.Demo"; the prefix IPM stands for "interprocess message." The MSMAIL.INI entry specifies a custom menu item in the Mail program window titled "Mail Demo_"; selecting this menu item will load the library APPEXEC.DLL and pass the command line \MAILDEMO\MAILDEMO.EXE --m <PARAMBLK> to that DLL. The binary 1s and 0s specify that this custom message type be recognized for composing, reading, replying, forwarding, printing, and saving of messages marked as having the type "MailDemo.Demo." The MSMAIL.INI entry must all be on one continuous line of text.

Message Data

The MS Mail system uses several data structures to encapsulate message information. Example 4 shows the definitions of the MapiMessage and MapiRecipDesc structures, which are defined in the MAPI.H header file supplied by Microsoft. The MapiMessage structure defines how an individual Mail message is organized. For example, the MapiMessage structure contains a pointer to the subject string (lpszSubject), a pointer to the contents of the message (lpszNoteText), and a pointer to a string used to identify unique message types (lpszMessageType). Messages are transmitted including information about who sent the message and everyone on the distribution list. Address information is organized using the MapiRecipDesc structure (Example 4). The MapiMessage structure contains pointers to two sets of MapiRecipDesc data. lpOriginator points to MapiRecipDesc data for the individual that sent the message, while lpRecips points to an array of one or more MapiRecipDesc entries for the people copied on the message-distribution list, including the originator. The long-integer value nRecipCount is used to store the number of entries in the MapiRecipDesc array pointed to by lpRecips. Messages can also include embedded files and OLE objects. At the bottom of the MapiMessage structure definition are the member variables nFileCount and lpFiles, which are used to organize embedded data. MAPI.H also includes the definition of the MapiFileDesc structure, which is used to store individual file and OLE entries.

Using the CMapiUtil Class

MAPIUTIL.H and MAPIUTIL.CPP (Listings One and Two) show how the MAPI functions exported by MAPI.DLL can be organized into a C++ class named CMapiUtil. CMapiUtil does not use every possible mail feature, but is sufficient for most projects. Table 2 summarizes the member functions of the CMapiUtil class.

Listing Three shows how the CMapiUtil class can be used to send a mail message. The Logon() member function either starts a new mail session or establishes a link to an existing session if MS Mail is already running. GetAddressList() displays the standard MS Mail address-list dialog box for the user to make selections. The SendMessage() function then uses the address list to distribute the message. FreeMessage() clears memory buffers used by the CMapiUtil class. Finally, Logoff() exits the mail session or simply severs the link if MS Mail was already running.

The complete MAILDEMO program, including executables and programmer notes, is available electronically; see "Availability," page 3. This program sends and receives both standard text messages and special message types. The application was written using Visual C++ 1.5 and the MFC library, plus the CMapiUtil class presented here.

Figure 1 Typical customized mail application. Figure 2 Inserting your own application into the MS Mail system.

Example 1: Reading the message data passed by APPEXEC.DLL.

int CTsrApp::ReadMessageFromMemory (char * psCmdLine)
{   // convert the handle from ASCII hex digits to a number
    HGLOBAL handle = (HGLOBAL) atol_hex (psCmdLine) ;
    if (handle == 0)
        return HANDLE_ERROR ;
    // get ownership of block from APPEXEC.DLL
    HGLOBAL hMem = GlobalReAlloc (handle, 0,
        GMEM_MODIFY | GMEM_MOVEABLE | GMEM_SHARE) ;
    if (hMem == NULL)
        return HANDLE_ERROR ;
    // and lock the block to access it's members
    PARAMBLK * pParamBlk = (PARAMBLK *) GlobalLock (hMem) ;
        // use the PARAMBLK data in the memory block here...
    GlobalUnlock (hMem) ;
    GlobalFree (hMem) ;
    return 0 ;
}

Example 2: The PARAMBLK structure defined in MAILEXTS.H.

typedef struct tagPARAMBLK
{
    WORD   wVersion;        // eg. 0x0300 for ver 3.0
    WORD   wCommand;        // eg. wcommandOpen (def. MAILEXTS.H)
    LPSTR  lpDllCmdLine;    // command line string for msg. type
    LPSTR  lpMessageIDList; // array of message identifiers
    WORD   wMessageIDCount; // no. items in lpmessageIDList
    HWND   hwndMail;        // the mail window handle
    HANDLE hinstMail;       // the mail instance handle
    LPSTR  lpHelpPath;      // the help file name (if any)
    DWORD  hlpID;           // the help file context ID
} PARAMBLK;

Example 3: Defining a custom message type within the MSMAIL.INI file.

[Custom Messages]
IPM.MailDemo.Demo=3.0;Mail;&Mail
    Demo...;2;\maildemo\APPEXEC.DLL;\maildemo\maildemo.EXE -m
    <PARAMBLK>;1111111000000000;Mail demo application;;;

Example 4: The MapiMessage and MapiRecipDesc structures from MAPI.H.

typedef struct
  {
    ULONG ulReserved;               // Reserved (Must be 0)
    LPSTR lpszSubject;              // Message Subject
    LPSTR lpszNoteText;             // Message Text
    LPSTR lpszMessageType;          // Message Class
    LPSTR lpszDateReceived;         // in YYYY/MM/DD HH:MM format
    LPSTR lpszConversationID;       // conversation thread ID
    FLAGS flFlags;                 // unread,return receipt
    lpMapiRecipDesc lpOriginator;   // Originator descriptor
    ULONG nRecipCount;              // Number of recipients
    lpMapiRecipDesc lpRecips;       // Recipient descriptors
    ULONG nFileCount;               // # of file attachments
    lpMapiFileDesc lpFiles;         // Attachment descriptors
  } MapiMessage, FAR * lpMapiMessage;
#define MAPI_UNREAD             0x00000001  // flFlags values
#define MAPI_RECEIPT_REQUESTED  0x00000002
#define MAPI_SENT               0x00000004
typedef struct
  {
    ULONG ulReserved;       // Reserved for future use
    ULONG ulRecipClass;     // Recipient class
                           // MAPI_TO, MAPI_CC, MAPI_BCC, MAPI_ORIG
    LPSTR lpszName;         // Recipient name
    LPSTR lpszAddress;      // Recipient address (optional)
    ULONG ulEIDSize;        // Count in bytes of size of pEntryID
    LPVOID lpEntryID;       // System-specific recipient reference
  } MapiRecipDesc, FAR * lpMapiRecipDesc;
#define MAPI_ORIG   0       // Recipient is message originator
#define MAPI_TO     1       // Recipient is a primary recipient
#define MAPI_CC     2       // Recipient is a copy recipient
#define MAPI_BCC    3       // Recipient is blind copy recipient

Table 1: Mail API functions exported by MAPI.DLL.


    Function            Description
    MAPIAddress         Uses the Mail addressing features.
    MAPIDeleteMail      Deletes a message.
    MAPIDetails         Provides details of an address-list entry.
    MAPIFindNext        Locates a message in the message queue.
    MAPIFreeBuffer      Deletes a buffer used by another MAPI function.
    MAPILogoff          Ends a Mail session.
    MAPILogon           Starts a new Mail session.
    MAPIReadMail        Accesses the data in a message.
    MAPIResolveName     Gets a unique address for a recipient.
    MAPISaveMail        Saves a message.
    MAPISendDocuments   Transmits files.
    MAPISendMail        Transmits a message.

Table 2: CMapiUtil member functions from MAPIUTIL.CPP.


Function                  Description

Logon()                   Loads MAPI.DLL into memory, obtains
                          pointers to the MAPI functions,
                          and starts a mail session.
GetAddressList()          Displays the standard Mail dialog box
                          for creating a distribution list.
                          The list is initially empty.
GetUpdatedAddressList()   Displays the standard Mail dialog box
                          for creating a distribution list.
                          The list is initialized with the names
                          saved by SaveAddressList().
                          FreeAddressList() Frees the buffers used
                          by the GetUpdatedAddressList function.
SendMessage()             Sends a message using the current address list.
ReadMessage()             Reads a message from the Mail system.
SaveAddressList()         Saves the distribution list from the last message.
FreeMessage()             Frees memory tied up with the last message.
Logoff()                  Logs off the mail session and unloads MAPI.DLL.
NoteText()                Returns a pointer to the contents of a message.
NoteLong()                Returns the number of bytes in the contents of a message.

Listing One


// mapiutil.h  header file for mapiutil.cpp, jim conger, 1994
#ifndef MAPIUTIL_H
#define MAPIUTIL_H
// MAPI function types (from mapi.h prototypes)
typedef ULONG (FAR PASCAL *LPMAPILOGON)(ULONG, LPSTR, LPSTR, FLAGS,
    ULONG, LPLHANDLE);
typedef ULONG (FAR PASCAL *LPMAPILOGOFF)(LHANDLE, ULONG, FLAGS, ULONG);
typedef ULONG (FAR PASCAL *LPMAPISENDMAIL)(LHANDLE, ULONG,
    lpMapiMessage, FLAGS, ULONG);
typedef ULONG (FAR PASCAL *LPMAPIADDRESS)(LHANDLE, ULONG, LPSTR, ULONG, 
    LPSTR, ULONG, lpMapiRecipDesc, FLAGS, ULONG, LPULONG, 
    lpMapiRecipDesc FAR *);
typedef ULONG (FAR PASCAL *LPMAPIREADMAIL)(LHANDLE, ULONG, LPSTR, FLAGS,
    ULONG, lpMapiMessage FAR *);
typedef ULONG (FAR PASCAL *LPMAPIRESOLVENAME)(LHANDLE, ULONG, LPSTR,
    FLAGS, ULONG, lpMapiRecipDesc FAR *);
typedef ULONG (FAR PASCAL *LPMAPIFREEBUFFER)(LPVOID);
class CMapiUtil
{
public:
    CMapiUtil () ;
    ~CMapiUtil () ;
private:
    HINSTANCE           m_hMAPI ;           // handle of MAPI.DLL
    unsigned long       m_MailHandle ;      // mail session handle
    MapiRecipDesc       m_MapiRecipDesc ;   // defined in MAPI.H
    ULONG               m_lRecipients ;     // number of recipients
    lpMapiRecipDesc     m_lpRecipList ;     // pointer to list of recips
    ULONG               m_lOldRecipients ;  // number of recipients
    lpMapiRecipDesc     m_lpOldRecipList ;  // last list of recips
    lpMapiMessage       m_lpMessage ;       // message data in memory
    CStringList         m_NameList ;        // string list of recipients
    LPMAPILOGON         lpMAPILogon ;       // pointers to functions in 
    LPMAPISENDMAIL      lpMAPISendMail ;    // mapi.dll
    LPMAPIFREEBUFFER    lpMAPIFreeBuffer ;
    LPMAPILOGOFF        lpMAPILogoff ;
    LPMAPIADDRESS       lpMAPIAddress ;
    LPMAPIREADMAIL      lpMAPIReadMail ;
    LPMAPIRESOLVENAME   lpMAPIResolveName ;
public:
    int     Logon (CWnd * pWnd) ;
    int     GetAddressList (CWnd * pWnd) ;
    int     GetUpdatedAddressList (CWnd * pWnd) ;
    void    FreeAddressList () ;
    int     SendMessage (CWnd * pWnd, MapiMessage * lpMessage) ;
    int     ReadMessage (CWnd * pWnd, LPSTR lpMessageID) ;
    void    SaveAddressList () ;
    void    FreeMessage () ;
    void    Logoff (CWnd * pWnd) ;
    char *  NoteText () ;
    int     NoteLong () ;
} ;
#endif // MAPIUTIL_H


Listing Two


// mapiutil.cpp  utility functions for working with mail api, jim conger, 1994
#include "stdafx.h"     // used by VC++ for standard MFC includes
#include "mapi.h"
#include "mailexts.h"
#include "mapiutil.h"
#include <stdlib.h>
CMapiUtil::CMapiUtil ()
{
    TRACE ("\nCMapiUtil constructor") ;
    m_hMAPI = NULL ;
    m_MailHandle = NULL ;
    m_lRecipients = 0 ;
    m_lpRecipList = NULL ;
    m_lOldRecipients = 0 ;
    m_lpOldRecipList = NULL ;
    m_lpMessage = NULL ;
}
CMapiUtil::~CMapiUtil ()    // allows mindless shutdown of mail
{
    TRACE ("\nCMapiUtil destructor") ;
    if (m_lpOldRecipList != NULL)
        delete m_lpOldRecipList ;
    if (m_lpMessage != NULL)
        (*lpMAPIFreeBuffer) (m_lpMessage) ;
    if (m_hMAPI != NULL)    
        ::FreeLibrary (m_hMAPI) ;
}
    // Load mapi.dll into memory, get function addresses, and logon
int CMapiUtil::Logon (CWnd * pWnd)
{
    TRACE ("\nCMapiUtil::Logon ()") ;
    ULONG lHwnd = (ULONG)(LPSTR) pWnd->GetSafeHwnd () ;
    m_hMAPI = ::LoadLibrary ("MAPI.DLL") ;// explicitly load MAPI.DLL
    if (m_hMAPI < HINSTANCE_ERROR)
        return 0 ;
                                          // get address of MAPILogon()
    lpMAPILogon = (LPMAPILOGON) ::GetProcAddress (m_hMAPI,"MAPILogon") ;
    if (lpMAPILogon == NULL)
        return 0 ;
    // if MAPILogon() was found, assume the other functions can be found
    lpMAPISendMail = (LPMAPISENDMAIL) 
        ::GetProcAddress (m_hMAPI, "MAPISendMail") ;
    lpMAPIFreeBuffer = (LPMAPIFREEBUFFER) 
        ::GetProcAddress (m_hMAPI, "MAPIFreeBuffer") ;
    lpMAPILogoff = (LPMAPILOGOFF) 
        ::GetProcAddress (m_hMAPI, "MAPILogoff") ;
    lpMAPIAddress = (LPMAPIADDRESS) 
        ::GetProcAddress (m_hMAPI, "MAPIAddress") ;
    lpMAPIReadMail = (LPMAPIREADMAIL) 
        ::GetProcAddress (m_hMAPI, "MAPIReadMail") ;
    lpMAPIResolveName = (LPMAPIRESOLVENAME) 
        ::GetProcAddress (m_hMAPI, "MAPIResolveName") ;
    
    // open a mail session - does nothing if a session is running
    ULONG lStatus =  (*lpMAPILogon) (lHwnd, NULL, NULL, 
        MAPI_LOGON_UI, 0, (LPLHANDLE) &m_MailHandle) ;
    if (lStatus != SUCCESS_SUCCESS)
        return 0 ;
    else
        return TRUE ;
}
    // Show empty address dialog box, and get selections from user
int CMapiUtil::GetAddressList (CWnd * pWnd)
{
    TRACE ("\nCMapiUtil::GetAddressList ()") ;
    ULONG lHwnd = (ULONG)(LPSTR) pWnd->GetSafeHwnd () ;
    
    long lStatus = (*lpMAPIAddress) ((LHANDLE) m_MailHandle, lHwnd,
         NULL, 2,NULL, 0, NULL, 0, 0, &m_lRecipients, &m_lpRecipList) ;
    return (int) lStatus ;
}
    // Show initialized address dialog box, get final selections 
int CMapiUtil::GetUpdatedAddressList (CWnd * pWnd)
{
    TRACE ("\nCMapiUtil::GetUpdatedAddressList ()") ;
    ULONG lHwnd = (ULONG)(LPSTR) pWnd->GetSafeHwnd () ;
    lpMapiRecipDesc lpRD ;
    
    if (m_lOldRecipients > 0)           // if there is a list of names   
    {
        if (m_lpOldRecipList != NULL)   
            delete m_lpOldRecipList ;
        m_lpOldRecipList = new MapiRecipDesc [m_lOldRecipients] ;
        ASSERT (m_lpOldRecipList) ;
        lpMapiRecipDesc lpMRD = m_lpOldRecipList ;  
        
        for (int i = 0 ; i < (int) m_lOldRecipients ; i++)
        {
            POSITION pos = m_NameList.FindIndex (i) ;
            ULONG lStatus = (*lpMAPIResolveName) (
                (LHANDLE) m_MailHandle, lHwnd, 
                (LPSTR) (const char *) m_NameList.GetAt (pos), 
                MAPI_DIALOG, 0, &lpRD) ;
            if (lStatus == SUCCESS_SUCCESS)
                lpMRD [i] = * lpRD ;    // copy recipient data to array
            else
            {
                delete m_lpOldRecipList ;
                m_lpOldRecipList = NULL ;
                m_lOldRecipients = 0 ;
                break ;
            }
        }
    }
    long lStatus = (*lpMAPIAddress) ((LHANDLE) m_MailHandle, lHwnd,
         NULL, 2, NULL, m_lOldRecipients, m_lpOldRecipList, 0, 0, 
         &m_lRecipients, &m_lpRecipList) ;
    return (int) lStatus ;
}
    // free the buffers tied up by the GetUpdatedAddressList() function
void CMapiUtil::FreeAddressList ()
{
    TRACE ("\nCMapiUtil::FreeAddressList ()") ;
    if (m_lpOldRecipList != NULL)   
    {
        delete m_lpOldRecipList ;   // delete array holding copies
        m_lpOldRecipList = NULL ;
        m_lOldRecipients = 0 ;    
    }    
}
    // Send the message, using addresses from GetAddressList()
int CMapiUtil::SendMessage (CWnd * pWnd, MapiMessage * lpMessage)
{
    TRACE ("\nCMapiUtil::SendMessage ()") ;
    ULONG lHwnd = (ULONG)(LPSTR) pWnd->GetSafeHwnd () ;
    m_MapiRecipDesc.ulReserved = 0 ;
    m_MapiRecipDesc.ulRecipClass = MAPI_ORIG ;
    m_MapiRecipDesc.lpszName = "TSR" ;
    m_MapiRecipDesc.lpszAddress = NULL ;
    lpMessage->lpOriginator = &m_MapiRecipDesc ;
    lpMessage->nRecipCount = m_lRecipients ;
    lpMessage->lpRecips = m_lpRecipList ;
    long lStatus = (*lpMAPISendMail) ((LHANDLE) m_MailHandle, lHwnd,
        lpMessage, 0L, 0L) ; 
    return (int) lStatus ;        
}
    // Read message identified by lpMessageID, save pointer to message
    // Returns TRUE if message was read OK, FALSE on error
int CMapiUtil::ReadMessage (CWnd * pWnd, LPSTR lpMessageID)
{
    TRACE ("\nCMapiUtil::ReadMessage ()") ;
    static lpMapiMessage lpMessage ;
    ULONG lHwnd = (ULONG)(LPSTR) pWnd->GetSafeHwnd () ;
    if (m_lpMessage != NULL)    // make sure last message is purged
        (*lpMAPIFreeBuffer) (m_lpMessage) ;
    if (m_lpRecipList != NULL)  // and clean up old address list
    {
        (*lpMAPIFreeBuffer) (m_lpRecipList) ;
        m_lpRecipList = NULL ;
    }
    m_lRecipients = 0 ;
                                // read the message
    ULONG lStatus = (*lpMAPIReadMail) (m_MailHandle, lHwnd, 
        lpMessageID, 0L, 0, &lpMessage) ;
    if (lStatus == SUCCESS_SUCCESS)
    {
        m_lpMessage = lpMessage ;   // save pointer to message if OK
        return TRUE ;               // and return TRUE
    }
    else
    {
        m_lpMessage = NULL ;    // otherwise, quit and return FALSE
        return FALSE ;
    }
}
    // save the names of all recipients in a message for use
    // in initializing the address dialog box in next mail send
void CMapiUtil::SaveAddressList ()
{
    TRACE ("\nCMapiUtil::SaveAddressList ()") ;
    if (m_lpMessage == NULL)
        return ;
    m_NameList.RemoveAll () ;   // empty the last list (if any)
    
    m_lOldRecipients = (long) m_lpMessage->nRecipCount ;
        // add all of the cc's to the end of the list
    for (int i = 0 ; i < (int) m_lpMessage->nRecipCount ; i++)
    {
        m_NameList.AddTail (m_lpMessage->lpRecips [i].lpszName) ;
    }
}
    // Free all buffers associated with a message
void CMapiUtil::FreeMessage ()
{
    TRACE ("\nCMapiUtil::FreeMessage ()") ;
    if (m_lpMessage != NULL)
    {
        (*lpMAPIFreeBuffer) (m_lpMessage) ;
        m_lpMessage = NULL ;
    }
    if (m_lpRecipList != NULL)
    {
        (*lpMAPIFreeBuffer) (m_lpRecipList) ;
        m_lpRecipList = NULL ;
        m_lRecipients = 0 ;
    }
}
    // Log off from mail, and release MAPI.DLL
void CMapiUtil::Logoff (CWnd * pWnd)
{    
    TRACE ("\nCMapiUtil::Logoff ()") ;
    ULONG lHwnd = (ULONG)(LPSTR) pWnd->GetSafeHwnd () ;
    if (m_MailHandle != 0)      
    {
        (*lpMAPILogoff) (m_MailHandle, lHwnd, 0L, 0L) ;
        m_MailHandle = 0 ;
    }
    if (m_hMAPI != NULL)    
    {
        ::FreeLibrary (m_hMAPI) ;
        m_hMAPI = NULL ;
    }
}
    // Returns a pointer to the text of the message, NULL if no message
char * CMapiUtil::NoteText ()
{
    TRACE ("\nCMapiUtil::NoteText ()") ;
    if (m_lpMessage != NULL)
        return m_lpMessage->lpszNoteText ;
    else
        return NULL ;
}
    // Returns number of chars in the text of the message, 0 if none
int CMapiUtil::NoteLong ()
{
    TRACE ("\nCMapiUtil::NoteLong ()") ;
    if (m_lpMessage != NULL)
        return ::lstrlen (m_lpMessage->lpszNoteText) ;
    else
        return 0 ;
}


Listing Three


void CMainFrame::OnMailSendText()
{
    CMapiUtil MapiUtil ;
    if (MapiUtil.Logon (this))

    {
        if (MapiUtil.GetAddressList (this) == SUCCESS_SUCCESS)
        {
            MapiMessage Message ;
            Message.ulReserved = 0 ;
            Message.lpszSubject = "Message subject" ;
            Message.lpszNoteText = "Text of the message." ;
            Message.lpszMessageType = NULL ; // standard msg. 
            Message.lpszDateReceived = "1994/01/01 12:00" ;
            Message.lpszConversationID = NULL ;
            Message.flFlags = MAPI_UNREAD | MAPI_DIALOG ;
            Message.lpOriginator = NULL;
            Message.nRecipCount = 0 ; 
            Message.lpRecips = NULL ;    
            Message.nFileCount = 0 ;  
            Message.lpFiles = NULL ;     
            MapiUtil.SendMessage (this, &Message) ; 
            MapiUtil.FreeMessage () ;
        }
        MapiUtil.Logoff (this) ;
    }
    else
        MessageBox ("Could not log on to MS Mail.", "Error",
            MB_ICONEXCLAMATION | MB_OK) ;
}

Copyright © 1994, Dr. Dobb's Journal