Chapter 6

Creating MAPI-Aware Applications


CONTENTS


The most basic MAPI service is the ability to provide a send feature to a program. Almost all Windows programs have a print feature to send output to a print device. The send feature works basically the same way. It provides the user a way to send output to some other e-mail address. Adding this most basic form of MAPI service to your Windows applications makes it "MAPI-aware." MAPI-aware applications do not have e-mail services as a basic part of their functionality (that is, an e-mail client) but provide it as an added feature. For example, most office suite applications (word processing, spreadsheet, and so on) provide a send feature on the main menu of all their programs. Basically, whatever documents you can create with the program can be sent to other locations using the mail services available on the network.

In this chapter, you'll learn how to make your programs MAPI-aware using the Simple MAPI API call set. This API set provides very easy, very quick access to the most needed MAPI services. Another advantage of using the API set is that it is available to any program that supports DLL calls. This means it is quite easy to add MAPI services to most any Windows application.

In the first half of this chapter, you'll get a quick overview of the API calls themselves. You'll learn about the eleven API calls and three user-defined types that comprise the Simple MAPI interface, and you'll build a set of examples that illustrate the use of Simple MAPI services.

In the second half of the chapter, you'll create some real-world examples of Windows applications that have MAPI-aware features. You'll create a quick spreadsheet routine that can send its results using MAPI. You'll also modify an existing Visual Basic 4.0 program to add MAPI capabilities.

When you complete this chapter, you'll have a good understanding of the Microsoft MAPI API calls. You will also be able to design and build applications that can use the MAPI interface to provide mail services from within your Visual Basic programs.

The Simple MAPI API Calls

The Simple MAPI (SMAPI) calls allow you to add MAPI services to virtually any Windows program. While these calls offer only the smallest set of MAPI services, they are still quite useful. In the next few sections, you'll learn about the three user-defined structures needed to provide MAPI via the API calls, and you'll experiment with each of the API calls themselves.

Note
All the SMAPI services for Visual Basic and VBA applications are provided through the dynamic link library (DLL) called VBAMAP32.DLL (or VBAMAPI.DLL for 16-bit plat-forms). If you do not already have this DLL on your system, you can find it on the CD-ROM that ships with this book.

Before you begin this part of the chapter, start Visual Basic 4.0 and begin a new project. Locate the VBAMAP32.BAS module in the Chap06 folder and add that module to your project. This has all the API calls and structures defined along with several constants and a helper error function.

Note
Throughout this chapter, you'll use the 32-bit version of the SMAPI set. A 16-bit version of the SMAPI calls can also be used. You'll find the 16-bit version of the API calls in the VBAMAP16.BAS module on the CD-ROM.

The User-Defined Types

Simple MAPI defines three structures for passing information

MAPIMessage

The MAPIMessage structure is used to hold all the vital information about a message packet. You will use this structure to pass message data from your programs to the DLL and back. Table 6.1 shows the structure of the MAPIMessage along with short descriptions for each element.

Table 6.1. The MAPIMessage structure.
FieldType Description
Reserved LongReserved for future use. This field must be 0.
Subject StringThe subject text, limited to 256 characters or fewer. (Messages saved using MAPISaveMail are not limited to 256 characters.) An empty string indicates no subject text.
NoteText StringA string containing text in the message. An empty string indicates no text. For inbound messages, each paragraph is terminated with a carriage return-line feed pair (0x0d0a). For outbound messages, paragraphs can be delimited with a carriage return, a line feed, or a carriage return-line feed pair (0x0d, 0x0a, or 0x0d0a, respectively).
MessageType StringA message type string used by applications other than interpersonal electronic mail. An empty string indicates an interpersonal message (IPM) type.
DateReceived StringA string indicating the date a message is received. The format is YYYY/MM/DD HH:MM; hours are measured on a 24-hour clock.
ConversationID StringA string indicating the conversation thread ID to which this message belongs.
Flags LongA bitmask of flags. Unused flags are reserved. Unused flags must be 0 for outbound messages and are ignored for inbound messages. The following flags are defined:
MAPI_RECEIPT_REQUESTED
MAPI_SENT
MAPI_UNREAD
RecipCount LongA count of the recipient descriptor types pointed to by Recips. A value of 0 indicates that no recipients are included.
FileCount LongA count of the file attachment descriptor types pointed to by Files. A value of 0 indicates that no file attachments are included.

Listing 6.1 shows how the MAPIMessage structure is built using Visual Basic 4.0.

Note
The user-defined types and API calls are all contained in the VBAMAP32.BAS and VBAMAPI16.BAS modules on the CD-ROM. You do not have to type these structures and API calls into your projects.

Listing 6.1. The MAPIMessage user-defined type.
'***************************************************
'   MAPI Message holds information about a message
'***************************************************

Type MapiMessage
    Reserved As Long
    Subject As String
    NoteText As String
    MessageType As String
    DateReceived As String
    ConversationID As String
    Flags As Long
    RecipCount As Long
    FileCount As Long
End Type

MAPIRecip

The MAPIRecip structure holds all the important data related to a message recipient. Table 6.2 describes the structure, and Listing 6.2 shows how it looks in VBA code.

Table 6.2. The MAPIRecip structure.
FieldType Description
Reserved LongReserved for future use. This field must be 0.
RecipClass LongClassifies the recipient of the message. (Different classes can be used to sort messages by the recipient class.) It can also contain information about the originator of an inbound message.
Name StringThe name of the recipient that is displayed by Mail.
Address StringProvider-specific message delivery data. This can be used by the message system to identify recipients who are not in an address list (one-off addresses).
EIDSize LongThe size (in bytes) of the opaque binary data in EntryID.
EntryID StringA binary string used by Mail to efficiently specify the recipient. Unlike the Address field, this data is opaque and is not printable. Mail returns valid EntryIDs for recipients or originators included in the address list.


Listing 6.2. The MAPIRecip user-defined type.
'************************************************
'   MAPIRecip holds information about a message
'   originator or recipient
'************************************************

Type MapiRecip
    Reserved As Long
    RecipClass As Long
    Name As String
    Address As String
    EIDSize As Long
    EntryID As String
End Type

MAPIFile

The last structure used by SMAPI is the MAPIFile structure. This user-defined type holds all the information about a message attachment. Table 6.3 describes the structure, and Listing 6.3 shows the UDT definition.

Table 6.3. The MAPIFile structure.
FieldType Description
Reserved LongReserved for future use. This field must be 0.
Flags LongA bitmask of flags. Unused flags are reserved and must be 0. The following flags are defined:
MAPI_OLE
MAPI_OLE_STATIC
MAPI_OLE
is set if the attachment is an OLE object. If MAPI_OLE_STATIC is also set, the attachment is a static OLE object rather than an embedded OLE object.
Position LongAn integer describing where the attachment should be placed in the message body. Attachments replace the character found at a certain position in the message body; in other words, attachments replace the MapiMessage type field NoteText[Position]. Applications may not place two attachments in the same location within a message, and attachments may not be placed beyond the end of the message body.
FieldTypeDescription
PathName StringThe full pathname of the attached file. The file should be closed before this call is made.
FileName StringThe filename seen by the recipient. This name may differ from the filename in PathName if temporary files are being used. If FileName is empty, the filename from PathName is used. If the attachment is an OLE object, FileName contains the class name of the object; for example, "Microsoft Excel Worksheet."
FileType LongA reserved descriptor that is used to indicate to the recipient the type of the attached file. An empty string indicates an unknown or operating system-determined file type. Use 0 for this parameter at all times.


Listing 6.3. The MAPIFile user-defined type.
'******************************************************
'   MapiFile holds information about file attachments
'******************************************************

Type MapiFile
    Reserved As Long
    Flags As Long
    Position As Long
    PathName As String
    FileName As String
    FileType As Long
End Type

These are the only three structures needed to establish MAPI services with the VBAMAPI DLLs. The next section describes each of the API calls and constants and shows you examples of how to use them.

The API Functions

There are eleven SMAPI API calls. This set of calls provides access to the core MAPI services including

The next several sections describe each of the API calls and provide Visual Basic 4.0 examples of how to use them.

If you haven't already done so, start Visual Basic 4.0 and load the VBAMAP32.BAS module into your project. Listing 6.4 shows the complete set of API calls for SMAPI. You do not have to type this information into your project. You can find this module in the Chap06 directory that was created when you installed the source code from the CD-ROM.


Listing 6.4. The Simple MAPI API call declarations.
'***************************
'   FUncTION Declarations
'***************************

Declare Function MAPILogon Lib "VBAMAP32.DLL" Alias "BMAPILogon" (ByVal UIParam&, ÂByVal User$, ByVal Password$, ByVal Flags&, ByVal Reserved&, Session&) As Long

Declare Function MAPILogoff Lib "VBAMAP32.DLL" Alias "BMAPILogoff" (ByVal Session&, ÂByVal UIParam&, ByVal Flags&, ByVal Reserved&) As Long

Declare Function MAPIDetails Lib "VBAMAP32.DLL" Alias "BMAPIDetails" (ByVal ÂSession&, ByVal UIParam&, Recipient As MapiRecip, ByVal Flags&, ByVal Reserved&) ÂAs Long

Declare Function MAPIResolveName Lib "VBAMAP32.DLL" Alias "BMAPIResolveName" (ByVal ÂSession&, ByVal UIParam&, ByVal UserName$, ByVal Flags&, ByVal Reserved&, ÂRecipient As MapiRecip) As Long

Declare Function MAPISendDocuments Lib "VBAMAP32.DLL" Alias "BMAPISendDocuments" Â(ByVal UIParam&, ByVal DelimStr$, ByVal FilePaths$, ByVal FileNames$, ByVal ÂReserved&) As Long

Declare Function MAPIFindNext Lib "VBAMAP32.DLL" Alias "BMAPIFindNext" (ByVal ÂSession&, ByVal UIParam&, ByVal MsgType$, ByVal SeedMsgID$, ByVal Flag&, ByVal ÂReserved&, MsgID$) As Long

Declare Function MAPIDeleteMail Lib "VBAMAP32.DLL" Alias "BMAPIDeleteMail" (ByVal ÂSession&, ByVal UIParam&, ByVal MsgID$, ByVal Flags&, ByVal Reserved&) As Long

Declare Function MAPIAddress Lib "VBAMAP32.DLL" Alias "BMAPIAddress" (ByVal ÂSession&, ByVal UIParam&, ByVal Caption$, ByVal EditFields&, ByVal Label$, ÂRecipCount&, Recipients() As MapiRecip, ByVal Flags&, ByVal Reserved&) As Long

Declare Function MAPISaveMail Lib "VBAMAP32.DLL" Alias "BMAPISaveMail" (ByVal ÂSession&, ByVal UIParam&, Message As MapiMessage, Recipient As MapiRecip, File As ÂMapiFile, ByVal Reserved&, MsgID$) As Long

Declare Function MAPISendMail Lib "VBAMAP32.DLL" Alias "BMAPISendMail" (ByVal ÂSession&, ByVal UIParam&, Message As MapiMessage, Recipient As MapiRecip, File As ÂMapiFile, ByVal Flags&, ByVal Reserved&) As Long

Declare Function MAPIReadMail Lib "VBAMAP32.DLL" Alias "BMAPIReadMail" (ByVal ÂSession&, ByVal UIParam&, ByVal MsgID$, ByVal Flags&, ByVal Reserved&, Message As ÂMapiMessage, Originator As MapiRecip, recips() As MapiRecip, files() As MapiFile) ÂAs Long

There are also a number of CONSTANT declarations needed to make the API calls easier to work with. Listing 6.5 shows the error constants and flag declarations used for SMAPI.


Listing 6.5. The SMAPI constants.
'**************************
'   CONSTANT Declarations
'**************************
'

Global Const SUccESS_SUccESS = 0
Global Const MAPI_USER_ABORT = 1
Global Const MAPI_E_FAILURE = 2
Global Const MAPI_E_LOGIN_FAILURE = 3
Global Const MAPI_E_DISK_FULL = 4
Global Const MAPI_E_INSUFFICIENT_MEMORY = 5
Global Const MAPI_E_BLK_TOO_SMALL = 6
Global Const MAPI_E_TOO_MANY_SESSIONS = 8
Global Const MAPI_E_TOO_MANY_FILES = 9
Global Const MAPI_E_TOO_MANY_RECIPIENTS = 10
Global Const MAPI_E_ATTAchMENT_NOT_FOUND = 11
Global Const MAPI_E_ATTAchMENT_OPEN_FAILURE = 12
Global Const MAPI_E_ATTAchMENT_WRITE_FAILURE = 13
Global Const MAPI_E_UNKNOWN_RECIPIENT = 14
Global Const MAPI_E_BAD_RECIPTYPE = 15
Global Const MAPI_E_NO_MESSAGES = 16
Global Const MAPI_E_INVALID_MESSAGE = 17
Global Const MAPI_E_TEXT_TOO_LARGE = 18
Global Const MAPI_E_INVALID_SESSION = 19
Global Const MAPI_E_TYPE_NOT_SUPPORTED = 20
Global Const MAPI_E_AMBIGUOUS_RECIPIENT = 21
Global Const MAPI_E_MESSAGE_IN_USE = 22
Global Const MAPI_E_NETWORK_FAILURE = 23
Global Const MAPI_E_INVALID_EDITFIELDS = 24
Global Const MAPI_E_INVALID_RECIPS = 25
Global Const MAPI_E_NOT_SUPPORTED = 26

Global Const MAPI_E_NO_LIBRARY = 999
Global Const MAPI_E_INVALID_PARAMETER = 998

Global Const MAPI_ORIG = 0
Global Const MAPI_TO = 1
Global Const MAPI_cc = 2
Global Const MAPI_Bcc = 3

Global Const MAPI_UNREAD = 1
Global Const MAPI_RECEIPT_REQUESTED = 2
Global Const MAPI_SENT = 4


Listing 6.5. continued
'***********************
'   FLAG Declarations
'***********************

Global Const MAPI_LOGON_UI = &H1
Global Const MAPI_NEW_SESSION = &H2
Global Const MAPI_DIALOG = &H8
Global Const MAPI_UNREAD_ONLY = &H20
Global Const MAPI_ENVELOPE_ONLY = &H40
Global Const MAPI_PEEK = &H80
Global Const MAPI_GUARANTEE_FIFO = &H100
Global Const MAPI_BODY_AS_FILE = &H200
Global Const MAPI_AB_NOMODIFY = &H400
Global Const MAPI_SUPPRESS_ATTAch = &H800
Global Const MAPI_FORCE_DOWNLOAD = &H1000

Global Const MAPI_OLE = &H1
Global Const MAPI_OLE_STATIC = &H2

These are all the basic tools needed to begin to write MAPI applications. The next section reviews each API call in greater depth, including at least one coding example for each call.

Warning
In order for the 32-bit API calls to work, you must have the VBAMAP32.DLL in your WINDOWS\SYSTEM folder. If you are using Visual Basic 4.0 on a 16-bit platform, you can load the VBAMAPI.BAS module and make sure that the VBAMAPI.DLL is in your WINDOWS\SYSTEM folder.

MAPIErr-An Added Helper Function

All SMAPI calls return a status code (either SUccESS or some error). You should always check this value before continuing on with your program. In order to make it easier to work with the SMAPI calls, you can add a helper function that returns meaningful error messages for the established MAPI errors. Add a BAS module to your Visual Basic project called MAPIERR.BAS and enter the code in Listing 6.6.


Listing 6.6. Adding the MAPIErr function.
Public Function MapiErr(lError) As String
    '
    ' return displayable string for error
    '
    Dim cRtn As String
    '
    Select Case lError
        Case MAPI_USER_ABORT ' 1
            cRtn = "MAPI User Cancel"
        Case MAPI_E_FAILURE ' 2
            cRtn = "MAPI Failure"
        Case MAPI_E_LOGIN_FAILURE ' 3
            cRtn = "MAPI Login failure"
        Case MAPI_E_DISK_FULL ' 4
            cRtn = "MAPI Disk full"
        Case MAPI_E_INSUFFICIENT_MEMORY ' 5
            cRtn = "MAPI Insufficient memory"
        Case MAPI_E_BLK_TOO_SMALL ' 6
            cRtn = "MAPI Block too small"
        Case MAPI_E_TOO_MANY_SESSIONS ' 8
            cRtn = "MAPI Too many sessions"
        Case MAPI_E_TOO_MANY_FILES ' 9
            cRtn = "MAPI too many files"
        Case MAPI_E_TOO_MANY_RECIPIENTS ' 10
            cRtn = "MAPI Too many attachments"
        Case MAPI_E_ATTAchMENT_NOT_FOUND ' 11
            cRtn = "MAPI Attachment not found"
        Case MAPI_E_ATTAchMENT_OPEN_FAILURE ' 12
            cRtn = "MAPI Attachment open failure"
        Case MAPI_E_ATTAchMENT_WRITE_FAILURE ' 13
            cRtn = "MAPI Attachment Write Failure"
        Case MAPI_E_UNKNOWN_RECIPIENT ' 14
            cRtn = "MAPI Unknown recipient"
        Case MAPI_E_BAD_RECIPTYPE ' 15
            cRtn = "MAPI Bad recipient type"
        Case MAPI_E_NO_MESSAGES ' 16
            cRtn = "MAPI No messages"
        Case MAPI_E_INVALID_MESSAGE ' 17
            cRtn = "MAPI Invalid message"
        Case MAPI_E_TEXT_TOO_LARGE ' 18
            cRtn = "MAPI Text too large"
        Case MAPI_E_INVALID_SESSION ' 19
            cRtn = "MAPI Invalid session"
        Case MAPI_E_TYPE_NOT_SUPPORTED ' 20
            cRtn = "MAPI Type not supported"
        Case MAPI_E_AMBIGUOUS_RECIPIENT ' 21
            cRtn = "MAPI Ambiguous recipient"
        Case MAPI_E_MESSAGE_IN_USE ' 22
            cRtn = "MAPI Message in use"
        Case MAPI_E_NETWORK_FAILURE ' 23
            cRtn = "MAPI Network failure"
        Case MAPI_E_INVALID_EDITFIELDS ' 24
            cRtn = "MAPI Invalid edit fields"
        Case MAPI_E_INVALID_RECIPS ' 25
            cRtn = "MAPI Invalid Recipients"
        Case MAPI_E_NOT_SUPPORTED ' 26
            cRtn = "MAPI Not supported"
        Case MAPI_E_NO_LIBRARY ' 999
            cRtn = "MAPI No Library"
        Case MAPI_E_INVALID_PARAMETER ' 998
            cRtn = "MAPI Invalid parameter"
    End Select
    '
    MapiErr = cRtn & " [" & CStr(lError) & "]"
    '
End Function

Now you're ready to start coding your SMAPI examples.

MAPILogon and MAPILogOff

The MAPILogon and MAPILogOff functions are used to start and stop MAPI sessions.

Note
It is always a good idea to log off a session when you no longer need MAPI services. Leaving an unused session open can slow your program and, if it's left open after you exit, can lead to unexpected problems.

Table 6.4 shows the MAPILogon parameters along with their type and description.

Table 6.4. The MAPILogon parameters.
ParameterType Description
UIParam LongThe parent window handle for the dialog box. A value of 0 specifies that any dialog box displayed is application modal.
User StringA user account name. An empty string indicates that a sign-in dialog box with an empty name field should be generated (if the appropriate flag is set).
Password StringThe user's MAPI password. An empty string indicates that a sign-in dialog box with an empty password field should be generated (if the appropriate flag is set) or that MAPI does not expect a password.
Flags LongA bitmask of flags. The following flags are defined:
MAPI_LOGON_UI=&H1
MAPI_NEW_SESSION=&H2
MAPI_FORCE-DOWNLOAD=&H1000
Reserved LongReserved for future use. This parameter must be 0.
Session LongA unique session handle whose value is set by MAPI when the MAPILogon call is successful. The session handle can then be used in subsequent MAPI calls.

Table 6.5 shows the MAPILogOff parameters along with their type and description.

Table 6.5. The MAPILogOff parameters.
ParameterType Description
Session LongA unique MAPI-assigned session handle whose value represents an already existing MAPI session.
UIParam LongThe parent window handle for the dialog box. A value of 0 specifies that any dialog box displayed is application modal.
Flags LongReserved for future use. This parameter must be 0.
Reserved LongReserved for future use. This parameter must be 0.

Add a new command button to your Visual Basic form. Set its Caption property to LogOn. Use Edit|Copy, Edit|Paste to add a second command button as part of a control array. Set the second command button's caption to LogOff. Then add the code in Listing 6.7 to the Command1_Click event.


Listing 6.7. Adding code to the Command1_Click event.
Private Sub Command1_Click(Index As Integer)
    '
    ' handle button press
    '
    Select Case Index
        Case 0 ' log on session
            SMAPIStart
        Case 1 ' log off session
            SMAPIEnd
    End Select
    '
End Sub

Next add the following form-level declarations to the general declaration area of your form. You'll use these throughout the project.

Option Explicit
'
Dim lReturn As Long ' return flag
Dim lSession As Long ' session handle
Dim udtMessage As MapiMessage ' message object
Dim udtRecip As MapiRecip ' recipient object
Dim udtRecips() As MapiRecip ' recipient collection
Dim udtFile As MapiFile ' attachment object
Dim udtFiles() As MapiFile ' attachment collection

Now add a new subroutine called SMAPIStart to the project, and enter the code shown in Listing 6.8.


Listing 6.8. Adding the SMAPIStart routine.
Public Sub SMAPIStart()
    '
    ' start an SMAPI session
    '
    lReturn = MAPILogon(Me.hWnd, "", "", MAPI_LOGON_UI, 0, lSession)
    If lReturn <> SUccESS_SUccESS Then
        MAPIErr (lReturn)
    End If
    '
End Sub

Finally, add the SMAPIEnd routine, and enter the code shown in Listing 6.9.


Listing 6.9. Adding the SMAPIEnd routine.
Public Sub SMAPIEnd()
    '
    ' end an SMAPI session
    '
    lReturn = MAPILogoff(lSession, Me.hWnd, 0, 0)
    If lReturn <> SUccESS_SUccESS Then
        MAPIErr (lReturn)
    Else
        MsgBox "MAPI Session Closed", vbInformation, "SMAPI LogOff"
    End If
    '
End Sub

Now save the form as SMAPI.FRM and the project as SMAPI.VBP. When you run the project, click the LogOn button to bring up the logon dialog box (see Figure 6.1).

Figure 6.1 : The logon dialog box.

MAPIAddress

The MAPIAddress call produces the address book dialog box and allows users to add, edit, and delete records from the address book. There are several flags you can use to control the address book dialog box behavior. Table 6.6 shows the MAPIAddress call parameters and their type and description.

Table 6.6. The MAPIAddress parameters.
ParameterType Description
Session LongA unique MAPI-assigned session handle whose value represents a session with the messaging subsystem. The session handle is returned by MAPILogon and invalidated by MAPILogoff. If the value is 0, MAPI initiates a session from a system default session (if one exists) or presents a sign-in dialog box.
UIParam LongThe parent window handle for the dialog box. A value of 0 specifies that any dialog box displayed is application modal.
Caption StringThe caption of the address list dialog box. If this parameter is an empty string, the default value "Address Book" is used.
EditFields StringThe number of edit controls that should be present in the address list. The values 0 to 4 are valid. The edit values are defined as:
ReadOnly(0)
To(1)
cc(2)
Bcc(3)
If EditFields is 1 and more than one kind of entry exists in Recips, Label is ignored.
Label StringA string used as an edit control label in the address list dialog box. This argument is ignored and should be an empty string except when EditFields is 1.
RecipCount LongThe number of entries in Recipients. If RecipCount is 0, Recipients is ignored.
Recipients() MAPIRecipThe initial array of recipient entries to be used to populate edit controls in the address list dialog box. This array is re-dimensioned as necessary to accommodate the entries made by the user in the address list dialog box.
Flags LongA bitmask of flags. Unspecified flags should always be passed as 0. Undocumented flags are reserved. The following flags are defined:
MAPI_LOGON_UI=&H1
MAPI_NEW_SESSION=&H2
Reserved LongReserved for future use. This parameter must be 0.

Now add a new button to the control array and set its caption to AddressBook. Then modify the Command1_Click event to match the code in Listing 6.10.


Listing 6.10. Modifying the Command1_Click event.
Private Sub Command1_Click(Index As Integer)
    '
    ' handle button press
    '
    Select Case Index
        Case 0 ' log on session
            SMAPIStart
        Case 1 ' log off session
            SMAPIEnd
        Case 2 ' addressbook
            AddressBook
    End Select
    '
End Sub

Next add the AddressBook subroutine and enter the code shown in Listing 6.11.


Listing 6.11. Adding the AddressBook routine.
Public Sub AddressBook()
    '
    ' call up the address book
    '
    On Error Resume Next
    '
    lReturn = MAPIAddress(lSession, Me.hWnd, "SMAPI Address Book", 3, "", 0, ÂudtRecips(), 0, 0)
    If lReturn <> SUccESS_SUccESS Then
        MsgBox MAPIErr(lReturn)
    End If
    '
    MsgBox "Selected Recipients: " & CStr(UBound(udtRecips) + 1), vbInformation, Â"AddressBook"
    '
End Sub

The AddressBook routine calls up the MAPI address book, passing a new dialog title, and enabling all possible recipient class buttons (TO:, cc:, and Bcc:). The AddressBook function returns a collection of recipients.

Save and run the project. After clicking the AddressBook, you should see something like the screen in Figure 6.2.

Figure 6.2 : Viewing the address book.

MAPIResolveName

The MAPIResolveName function is used to look up and/or validate a recipient object. You can use this to retrieve the complete e-mail address of a recipient and to present a dialog box to the user to resolve any unknown or ambiguous names. The MAPIResolveName parameters are described in Table 6.7.

Table 6.7. The MAPIResolveName parameters.
ParameterType Description
Session LongA unique, MAPI-assigned session handle whose value represents a session with the messaging subsystem. The session handle is returned by MAPILogon and invalidated by MAPILogoff. If the value is 0, MAPI initiates a session from a system default session (if one exists) or by presenting a sign-in dialog box.
UIParam LongThe parent window handle for the dialog box. A value of 0 specifies that any dialog box displayed is application modal.
UserName StringA string containing the name to be resolved.
Flags LongA bitmask of flags. The following flags are defined:
MAPI_LOGON_UI=&H1 (display logon dialog)
MAPI_NEW_SESSION=&H2 (start new session)
MAPI_DIALOG=&H8 (show resolve dialog)
MAPI_AB_NOMODIFY=&H400 (no modify address book)
Reserved LongReserved for future use. This parameter must be 0.
Recipient MapiRecipA recipient type set by MAPIResolveName if the resolution results in a single match. The type contains the recipient information of the resolved name. The descriptor can then be used in calls to MAPISendMail, MAPISaveMail, and MAPIAddress.

To test MAPIResolve, add a new button to the control array and set its caption to ResolveName. Then modify the Command1_Click event to match the one in Listing 6.12.


Listing 6.12. Modifying the Command1_Click event.
Private Sub Command1_Click(Index As Integer)
    '
    ' handle button press
    '
    Select Case Index
        Case 0 ' log on session
            SMAPIStart
        Case 1 ' log off session
            SMAPIEnd
        Case 2 ' addressbook
            AddressBook
        Case 3 ' resolve name
            ResolveName
    End Select
    '
End Sub

Now add the new ResolveName subroutine and enter the code in Listing 6.13.


Listing 6.13. Adding the ResolveName routine.
Public Sub ResolveName()
    '
    ' test resolvename service
    '
    lReturn = MAPIResolveName(lSession, Me.hWnd, "MCA", MAPI_DIALOG, 0, udtRecip)
    If lReturn <> SUccESS_SUccESS Then
        MsgBox MAPIErr(lReturn)
    End If
    '
End Sub

If you run this routine and supply an ambiguous name, MAPI returns a dialog box asking you to resolve the differences (see Figure 6.3).

Figure 6.3 : Viewing the ResolveName dialog box.

You can avoid viewing the dialog box (and just trap any error) by setting the Flag value to 0.

MAPIDetails

The MAPIDetails function returns a special dialog box that allows users to inspect and edit information about a single recipient. You can use this in your programs to give users direct access to an address entry edit form. Table 6.8 shows the MAPIDetails parameter list.

Table 6.8. The MAPIDetails parameters.
ParameterType Description
Session LongA unique session handle whose value represents a session with the messaging subsystem. Session handles are returned by MAPILogon and invalidated by MAPILogoff. If the value is 0, MAPI sets up a session from a system default session (if one exists) or by presenting a sign-in dialog box.
UIParam LongThe parent window handle for the dialog box. A value of 0 specifies that any dialog box displayed is application modal.
Recipient MAPIRecipA recipient descriptor containing the entry whose details are to be displayed. All fields of the MapiRecip type except EIDSize and EntryID are ignored. If the field EIDSize is zero, MAPI_E_AMBIG_RECIP is returned.
Flags LongA bitmask of flags. Unspecified flags should always be passed as 0. Undocumented flags are reserved. The following flags are defined:
MAPI_LOGON_UI=&H1 (force log on)
MAPI_NEW_SESSION=&H2 (force new session)
MAPI_AB_NOMODIFY=&H400 (no addrbook changes)
Reserved LongReserved for future use. This parameter must be 0.

Add a new button to the control array and set its caption to MAPIDetails. Then modify the Command1_Click event to match the code in Listing 6.14.


Listing 6.14. Modifying the Command1_Click event.
Private Sub Command1_Click(Index As Integer)
    '
    ' handle button press
    '
    Select Case Index
        Case 0 ' log on session
            SMAPIStart
        Case 1 ' log off session
            SMAPIEnd
        Case 2 ' addressbook
            AddressBook
        Case 3 ' resolve name
            ResolveName
        Case 4 ' addr details
            AddrDetails
    End Select
    '
End Sub

Now add the AddrDetails subroutine and fill it in with the code from Listing 6.15.


Listing 6.15. Adding the AddrDetails routine.
Public Sub AddrDetails()
    '
    ' show the details of a valid address
    '
    lReturn = MAPIResolveName(lSession, Me.hWnd, "MCA/Win", 0, 0, udtRecip)
    If lReturn <> SUccESS_SUccESS Then
        MsgBox MAPIErr(lReturn)
        Exit Sub
    End If
    '
    lReturn = MAPIDetails(lSession, Me.hWnd, udtRecip, MAPI_LOGON_UI, 0)
    If lReturn <> SUccESS_SUccESS Then
        MsgBox MAPIErr(lReturn)
    End If
    '
End Sub

When you save and run the project, you will see an address entry dialog box appear when you press the AddrDetails button (see Figure 6.4).

Figure 6.4 : Viewing the Address Book Details dialog box.

MAPISendDocuments

The MAPISendDocuments function is unique. You do not need to log in to MAPI before you call this function. As an option, you can fill simple test strings with information for attachments and pass them in the call, too. When the call is used, it brings up a full-featured compose dialog box that you can use to create and send an e-mail message. Table 6.9 shows the parameters for MAPISendDocuments.

Table 6.9. The MAPISendDocuments parameters.
ParameterType Description
UIParam LongThe parent window handle for the dialog box. A value of 0 specifies that the Send Note dialog box is application modal.
DelimChar StringA string containing the character used to delimit the names in the FilePaths and FileNames parameters. This character should not be used in filenames on your operating system.
FilePaths StringA string containing the list of full paths (including drive letters) for the attached files. The list is formed by concatenating correctly formed file paths separated by the character specified in the DelimChar parameter. The files specified in this parameter are added to the message as file attachments.
FileNames StringA string containing the list of the original filenames (in 8.3 format) as they should be displayed in the message. When multiple names are specified, the list is formed by concatenating the filenames separated by the character specified in the DelimChar parameter.
Reserved LongReserved for future use. This parameter must be 0.

Add another button to the control array and set its caption to SendDocs. Make sure your Command1_Click event matches the one in Listing 6.16.


Listing 6.16. Modifying the Command1_Click event.
Private Sub Command1_Click(Index As Integer)
    '
    ' handle button press
    '
    Select Case Index
        Case 0 ' log on session
            SMAPIStart
        Case 1 ' log off session
            SMAPIEnd
        Case 2 ' addressbook
            AddressBook
        Case 3 ' resolve name
            ResolveName
        Case 4 ' addr details
            AddrDetails
        Case 5 ' send documents
            SendDocs
    End Select
    '
End Sub

Now add the SendDocs subroutine and enter the code in Listing 6.17.


Listing 6.17. Adding the SendDocs routine.
Public Sub SendDocs()
    '
    ' start senddocuments
    '
    Dim cFiles As String
    Dim cNames As String
    Dim cDelim As String
    '
    cDelim = ";"
    cFiles = "C:\WINDOWS\WIN.INI;C:\CONFIG.SYS"
    cNames = "WIN.INI;CONFIG.SYS"
    '
    lReturn = MAPISendDocuments(Me.hWnd, cDelim, cFiles, cNames, 0)
    If lReturn <> SUccESS_SUccESS Then
        MsgBox MAPIErr(lReturn)
    End If
    '
End Sub

Note
The code in Listing 6.17 refers to documents in the C:\WINDOWS directory. If your Windows directory is not found at C:\WINDOWS, make the needed changes to the code example.

Save and run the project. Remember that you do not have to press LogOn before you press the SendDocs button. The MAPISendDocuments API will log you in automatically. Your screen should look similar to the one in Figure 6.5.

Figure 6.5 : The results of the SendDocs routine.

MAPISendMail

The MAPISendMail function is similar to MAPISendDocuments. The difference is that MAPISendMail uses the MAPIRecip and MAPIFile structures to pass data to MAPI. The MAPISendMail function also allows you to compose, address, and send a message without the use of any dialog boxes. Table 6.10 shows the MAPISendMail parameters.

Table 6.10. The MAPISendMail parameters.
ParameterType Description
Session LongAn opaque session handle whose value represents a session with the messaging subsystem. If the value is 0, Mail sets up a session either from a system default session (if one exists) or by presenting a sign-in dialog box. In all cases, Mail returns to its state before the call.
UIParam LongThe parent window handle for the dialog box. A value of 0 specifies that any dialog box displayed is application modal.
Message MapiMessage  
 Subject An empty string indicates no subject text. Some implementations may truncate subject lines that are too long or that contain carriage returns, line feeds, or other control characters.
 Note Text An empty string indicates no text. Each paragraph should be terminated with either a carriage return (0x0d), a line feed (0x0a), or a carriage return-line feed pair (0x0d0a). The implementation wraps lines as appropriate.
 Message Type A pointer to a string that is the message type. This field is for use by applications other than interpersonal mail (electronic forms, game message transmittal, and so on). For an interpersonal mail message (IPM), specify an empty string for this field.
Recips MapiRecips The first element of an array of recipients. When RecipCount is zero, this parameter is ignored.
Files MapiFiles The first element of an array of attachment files written when the message is read. The number of attachments per message may be limited in some systems. If the limit is exceeded, the error MAPI_E_TOO_MANY_FILES is returned. When FileCount is 0, this parameter is ignored.
Flags LongA bitmask of flags. The following flags are defined:
MAPI_LOGON_UI=&H1 (force logon)
MAPI_NEW_SESSION=&H2 (use a new session)
MAPI_DIALOG=&H8 (show send dialog box)
Reserved Long Reserved for future use. This parameter must be 0.

Add another button to the control array and set its caption to SendDialog. Update the Command1_Click event to match the code in Listing 6.18.


Listing 6.18. Updated Command1_Click event.
Private Sub Command1_Click(Index As Integer)
    '
    ' handle button press
    '
    Select Case Index
        Case 0 ' log on session
            SMAPIStart
        Case 1 ' log off session
            SMAPIEnd
        Case 2 ' addressbook
            AddressBook
        Case 3 ' resolve name
            ResolveName
        Case 4 ' addr details
            AddrDetails
        Case 5 ' send documents
            SendDocs
        Case 6 ' sendmail w/ dialog
            SendDialog
    End Select
    '
End Sub

Now add the SendDialog subroutine and enter the code from Listing 6.19.


Listing 6.19. Adding the SendDialog routine.
Public Sub SendDialog()
    '
    ' use sendmail w/ dialog
    '
    ' first build message
    udtMessage.Subject = "My Subject"
    udtMessage.NoteText = "This was written using VB Code"
    '
    ' next get valid recipient
    lReturn = MAPIResolveName(lSession, Me.hWnd, "MCA/Win", 0, 0, udtRecip)
    If lReturn <> SUccESS_SUccESS Then
        MsgBox MAPIErr(lReturn)
        Exit Sub
    End If
    '
    ' now add recipient to the message
    udtMessage.RecipCount = 1
    udtMessage.FilesCount = 0
    '
    ' now call sendmail w/ dialog
    lReturn = MAPISendMail(lSession, Me.hWnd, udtMessage, udtRecip, udtFile, ÂMAPI_DIALOG, 0)
    If lReturn <> SUccESS_SUccESS Then
        MsgBox MAPIErr(lReturn)
    End If
    '
End Sub

Save and run the project and press SendMail. You should see the Send Note dialog box on your screen, already filled out and ready to go (see Figure 6.6).

Figure 6.6 : The completed Send Note dialog box.

You can use MAPISendMail to send a message without invoking the Send Note dialog box. To do this, modify the MAPISendMail line by removing the MAPI_DIALOG constant and replacing it with 0.

MAPIFindNext and MAPIReadMail

The MAPIFindNext and MAPIReadMail functions are used to read messages that have been placed in the user's InBox. The MAPIFindNext function is used to point to the next (or first) unread message in the InBox. The MAPIReadMail function takes information received during the MAPIFindNext operation and retrieves the message for viewing or other processing. Table 6.11 contains a list of MAPIFindNext parameters.

Table 6.11. The MAPIFindNext parameters.
ParameterType Description
Session LongA unique session handle whose value represents a session with the messaging subsystem. Session handles are returned by MAPILogon and invalidated by MAPILogoff. If the value is 0, MAPIFindNext returns MAPI_E_INVALID_SESSION.
UIParam LongThe parent window handle for the dialog box. A value of 0 specifies that any dialog box displayed is application modal.
MessageType StringA pointer to a string that is the message type. To specify an interpersonal mail message, use an empty string, "".
SeedMessageID StringA string that is the message identifier seed for the request. If the identifier is an empty string, the first message matching the type specified in the MessageType parameter is returned.
Flags LongA bitmask of flags. Unspecified flags should always be passed as 0. Undocumented flags are reserved. The following flags are defined:
MAPI_UNREAD_ONLY=&H20 (new messages only)
MAPI_GUARANTEE_FIFO=&H100 (get oldest first)
Reserved longReserved for future use. This parameter must be 0.
MessageID StringA unique variable-length string that is the message identifier.

The MAPIReadMail function reads a message from the MAPI InBox and places it into the MAPIMessage structure. You use MAPIReadMail to retrieve messages from the Inbox for review and subsequent action. Table 6.12 shows the MAPIReadMail parameters.

Table 6.12. The MAPIReadMail parameters.
ParameterType Description
Session LongA unique session handle whose value represents a session with the messaging subsystem. If the value is 0, MAPIReadMail returns MAPI_E_INVALID_SESSION.
UIParam LongThe parent window handle for the dialog box. A value of 0 specifies that any dialog box displayed is application modal.
MessageID StringA variable-length string that is the message identifier of the message to be read. Message IDs can be obtained from the MAPIFindNext and MAPISaveMail functions.
Flags LongA bitmask of flags. Undocumented flags are reserved. The following flags are defined:
MAPI_ENVELOPE_ONLY=&H40 (only get headers)
MAPI_SUPPRESS_ATTAch=&H800 (no attachments)
MAPI_BODY_AS_FILE=&H200 (save body as an attachment)
MAPI_PEEK=&H80 (don't mark message as read).
Reserved LongReserved for future use. This parameter must be 0.
Message MAPIMessage A type set by MAPIReadMail to a message containing the message contents.
Originator MAPIRecip The originator of the message.
Recips ( ) MAPIRecip An array of recipients. This array is redimensioned as necessary to accommodate the number of recipients chosen by the user.
Files ( ) MAPIFiles An array of attachment files written when the message is read. When MAPIReadMail is called, all message attachments are written to temporary files. It is the caller's responsibility to delete these files when no longer needed. When MAPI_ENVELOPE_ ONLY or MAPI_SUPPRESS_ATTAch is set, no temporary files are written and no temporary names are filled into the file attachment descriptors. This array is re-dimensioned as necessary to accommodate the number of files attached by the user.

Now add another button to the control array and set its caption to ReadMail. Update the Command1_click event to match Listing 6.20.


Listing 6.20. Updated Command1_Click event.
Private Sub Command1_Click(Index As Integer)
    '
    ' handle button press
    '
    Select Case Index
        Case 0 ' log on session
            SMAPIStart
        Case 1 ' log off session
            SMAPIEnd
        Case 2 ' addressbook
            AddressBook
        Case 3 ' resolve name
            ResolveName
        Case 4 ' addr details
            AddrDetails
        Case 5 ' send documents
            SendDocs
        Case 6 ' sendmail w/ dialog
            SendDialog
        Case 7 ' read mail
            ReadMail
    End Select
    '
End Sub

Now add the ReadMail subroutine and enter the code from Listing 6.21.


Listing 6.21. Adding the ReadMail routine.
Public Sub ReadMail()
    '
    ' read the first message in the Inbox
    '
    Dim cMsgID As String
    Dim udtOrig As MapiRecip
    Dim cMsg As String
    Dim cMsgType As String
    '
    cMsgID = Space(256)
    cMsgType = ""
    '
    lReturn = MAPIFindNext(lSession, Me.hWnd, cMsgType, cMsgID, ÂMAPI_GUARANTEE_FIFO, 0, cMsgID)
    If lReturn <> SUccESS_SUccESS Then
        MsgBox MAPIErr(lReturn)
        Exit Sub
    End If
    '
    lReturn = MAPIReadMail(lSession, Me.hWnd, cMsgID, MAPI_PEEK, 0, udtMessage, ÂudtOrig, udtRecips, udtFiles)
    If lReturn <> SUccESS_SUccESS Then
        MsgBox MAPIErr(lReturn)
        Exit Sub
    End If
    '
    cMsg = cMsg & "Message.Subject: " & udtMessage.Subject & Chr(13)
    cMsg = cMsg & "Originator.Name: " & udtOrig.Name & Chr(13)
    MsgBox cMsg, vbInformation, "ReadMail"
    '
End Sub

Save and run the project. After you press the ReadMail button, you'll see a message box that shows the subject and sender name (see Figure 6.7).

Figure 6.7 : The results of MAPIReadMail.

Even though MAPI services provide a built-in compose form (see SendMail), there is no built-in read form. You must provide that through Visual Basic code.

Creating Mail-Aware Applications

The most basic form of MAPI applications is the mail-aware application. This is a program that offers mail services as an added feature. A good example of this is the send option in Word, Excel, Access, and the other Microsoft Office programs.

Making your programs mail-aware is about the same as making them aware of a printer. Usually, you can add a send option to the main menu and treat mail output the same way you treat printer output. It is possible that you may have to create an interim ASCII text file that you can then import into the message text using the clipboard or a few lines of Visual Basic code. All in all, it's quite easy.

In this section, you'll develop a send feature for an Excel spreadsheet and then modify a Visual Basic project to add MAPI-aware features to its menu.

Creating QIKMAIL.XLS with Excel

One of the quickest ways to add MAPI services to existing applications is through the use of the MAPISendDocuments API call. This API requires no user-defined types and does not even require that you perform a MAPI logon before attempting the send operation. All you need to do is add a MAPISendDocuments API declaration and write a short routine to handle the selection of files for the send.

All the Microsoft Office applications allow you to build this kind of MAPI service into your spreadsheets, input forms, and other projects. As an illustration, let's build a quick Excel spreadsheet that allows users to select from a friendly list of accounting reports and then route those reports to someone else in the company.

Note
This example uses Excel 95 and requires the VBAMAP32.DLL be present in the WINDOWS\SYSTEM folder. If you are running a 16-bit version of Excel, you need to have the VBAMAPI.DLL installed in your WINDOWS\SYSTEM folder, and you need to change the code referenced DLL to match your version.

First, bring up Excel and start a new worksheet. Insert a code module (Insert | Macro | Module) and enter the code shown in Listing 6.22.


Listing 6.22. Building a MAPI-aware Excel worksheet.
'
' declare API call for MAPI service
Declare Function MAPISendDocuments Lib "VBAMAP32.DLL" Alias "BMAPISendDocuments"
(ByVal UIParam&, ByVal DelimStr$, ByVal FilePaths$, ByVal FileNames$, ByVal Reserved&) As Long

'
' send file in active cell
'
Sub MAPIAware()
    '
    ' send the selected file as attachments
    '
    Dim x As Long ' for return
    Dim cFile As String
    Dim cName As String
    '
    If ActiveCell = "" Then
        MsgBox "Select a Report to Send"
        Exit Sub
    End If
    '
    cName = ActiveCell & ";"
    cFile = ActiveCell.Offset(0, 1) & ";"
    '
    x = MAPISendDocuments(0, ";", cFile, cName, 0)
    '
    If x <> 0 Then
        MsgBox "SendDocuments Error [" & Str(x) & "]"
    End If
    '
End Sub

Now select a new worksheet page and, using Figure 6.8 as a guide, enter the columns of information shown in Table 6.13.

Figure 6.8 : Laying out the QIKSEND.XLS worksheet.

Table 6.13. Column data for QIKSEND.XLS.
Column AColumn B
Reports On FileHidden Column
Last Month's SalesSLS9602.XLS
3rd Qtr BudgetBUDQ3.XLS
Monthly Cost ReportCOST9603.XLS
Department Fund BalancesFUNDBAL.XLS

Add a button to the worksheet (selected from the Forms Toolbar) and connect the button to the MAPIAware routine you built earlier. Set its caption to Send Report. Now hide column B so that users cannot see the exact operating system filenames. To do this, click the column header, click the right mouse button, and select Hide. Finally, add a title to the worksheet and save it as QIKSEND.XLS.

Now press Send Report. You'll be asked to log into the MAPI service; then MAPI will collect the file you selected and present you with the Send Note dialog box with the attachment already in place (see Figure 6.9).

Figure 6.9 : Sending attachments from Excel.

That's all there is to it! You can create much more sophisticated forms and options, though-including building the entire message, attaching the selected file, even routing directly to the person who is authorized to see the report. And all this can be done without ever asking the user to do more than select the report and click Send!

Next you'll add MAPI services to a Visual Basic project.

Adding MAPI Services to Existing Visual Basic 4.0 Programs

For this example, you'll borrow the code from a sample program that ships with Visual Basic 4.0 Standard Edition: the MDI sample application. This can be found in the SAMPLES\MDI folder within the main Visual Basic folder. If you do not have this application or if you want to leave your copy alone, you can find another copy of it on the CD-ROM shipped with this book.

This MDI application is a simple project that creates a multidocument editor that can save documents as ASCII files. To make this system mail-aware will require a few lines of code behind a Send... menu item in one form.

Note
This project uses the MAPI controls that ship with Visual Basic 4.0. You'll cover the MAPI controls in detail in the next chapter. For now, just remember that the MAPI controls offer the same level of access to MAPI services that the SMAPI API offers.

Load the MDI project and open the NOTEPAD form. First, add the MAPI Session and MAPI Message controls to the bottom of the form. Next, add a separator line and a Send... menu item just after the Save As... menu item (see Figure 6.10).

Figure 6.10. : Modifying the NOTEPAD form.

Finally, add the code in Listing 6.23 to the mnuFileSend_Click event. This is all the code you need to make this application mail-aware.


Listing 6.23. MAPI Send routine for NOTEPAD.
Private Sub mnuFileSend_Click()
    '
    ' log onto mail server
    ' start mail compose session
    ' log off mail server
    '
    On Error GoTo mnuFileSendErr
    '
    '
    MAPISession1.DownloadMail = False   ' dont check box
    MAPISession1.SignOn     ' start mail session
    MAPIMessages1.SessionID = MAPISession1.SessionID
    '
    ' handle sending msg
    MAPIMessages1.Compose   ' clear buffer
    MAPIMessages1.MsgNoteText=Me.Text1 ' move text to message
    MAPIMessages1.MsgSubject = Me.Caption ' get subject
    MAPIMessages1.Send True ' show server dialog
    '
    MAPISession1.SignOff    ' end mail session
    '
    Exit Sub
    '
mnuFileSendErr:
    MsgBox Error$, vbCritical, "Mail Send Error " + Str(Err)
    On Error Resume Next
    MAPISession1.SignOff
    '
End Sub

Notice that the DownloadMail property is set to skip over checking the Inbox. The Inbox isn't important here; you just want to send this document to someone via the mail server. The message text and message subject are set using data from the input form.

Now save and run the project. Begin to edit a new document (see Figure 6.11).

Figure 6.11 : Using the MDI application.

When you are done editing the text, select the Send... menu item to send the document out. You'll see the default compose form appear with the text and subject already supplied (see Figure 6.12).

Figure 6.12 : The MDI text ready to address and send.

There is a way to "bury" the mail features even deeper into this application. You really only need a way to tack on an address to this document. Listing 6.24 shows a modified routine that calls only the address dialog box and then sends the document out.

Note
In Listing 6.24, it is possible for the user to call the address book and exit it without selecting a valid address. This will be reported as an error when the Send method is invoked. To prevent the error, you could check the RecipAddress property before invoking the Send method.


Listing 6.24. Sending NOTEPAD using Address Book.
Private Sub mnuFileSend_Click()
    '
    ' log onto mail server
    ' start mail compose session
    ' log off mail server
    '
    On Error GoTo mnuFileSendErr
    '
    '
    MAPISession1.DownloadMail = False   ' dont check box
    MAPISession1.SignOn     ' start mail session
    MAPIMessages1.SessionID = MAPISession1.SessionID
    '
    ' handle sending msg
    MAPIMessages1.Compose   ' clear buffer
    MAPIMessages1.MsgNoteText = Me.Text1    ' get text
    MAPIMessages1.MsgSubject = Me.Caption   ' get subject
    MAPIMessages1.Show      ' get address
    MAPIMessages1.Send      ' send without dialog
    '
    MAPISession1.SignOff    ' end mail session
    '
    Exit Sub
    '
mnuFileSendErr:
    MsgBox Error$, vbCritical, "Mail Send Error " + Str(Err)
    On Error Resume Next
    MAPISession1.SignOff
    '
End Sub

Save and run this project. When you select the Send... menu option, you now will see only the address dialog box before the program sends your document out to the server.

As you can see, it's not at all difficult to add mail features to your existing applications. This technique of adding a send option to the menu will work with just about any Windows application.

Summary

In this chapter, you learned how to make your programs MAPI-aware using the Simple MAPI API call set. This API set provides very easy, very quick access to the most-needed MAPI services.

You learned that there are three user-defined types required to provide full SMAPI services:

You also learned that there are eleven API calls in the SMAPI set. This set of calls provides access to the core MAPI services, including

You also discovered that the MAPISendDocuments API call is the only MAPI call that requires no use of user-defined types to pass data via MAPI. This API call is very useful for adding quick MAPI support to existing applications.

In the second half of the chapter, you used SMAPI to add send features to an Excel worksheet (using the MAPISendDocuments API). You also modified an existing Visual Basic 4.0 project by adding a Send... menu option to the form.

In the next chapter, you'll get an in-depth look at the Visual Basic MAPI controls, and in the process you'll build a fully functional e-mail client application that you can use to read and write all your MAPI messages.