Sending a text message programmatically is simple. Assuming that you’ve already signed on with the MAPISession control and that you’ve set the MAPIMessages control’s SessionID property equal to the MAPISession control’s SessionID property, the following code does the job:
With MAPIMessages1 .Compose .MsgSubject = "This is the subject." .MsgNoteText = "This is the message body." .RecipIndex = 0 .RecipDisplayName = "Dave" .Send End With
Calling the MAPIMessages control’s Compose method tells the control that you are about to set some properties for a new outgoing message. Unlike incoming messages, there can never be more than one outgoing message at a time. The value of the MsgIndex property for the outgoing message is -1.
The MsgSubject and MsgNoteText properties are self-explanatory, being the subject and body portions of the message, respectively.
Unlike composing a message, there is no explicit method to call for adding a recipient, and the RecipIndex property is never -1. The number of recipients is controlled by how you set the RecipIndex property. In the code shown previously, the act of setting RecipIndex to automatically causes RecipCount to become 1. RecipCount is always automatically one greater than the highest value to which you have set RecipIndex. You never set RecipCount directly. The previously shown code can be modified to send to two recipients as follows:
With MAPIMessages1 .SessionID = MAPISession1.SessionID .Compose .MsgSubject = "This is the subject." .MsgNoteText = "This is the message body." .RecipIndex = 0 .RecipDisplayName = "Dave"
.RecipIndex = 1
.RecipDisplayName = "Annemarie".Send End With
The second recipient was added by incrementing RecipIndex and setting RecipDisplayName to a new name. Note that you can’t assign a variant string array to RecipDisplayName to reduce coding; the control’s type library identifies this property as a String, so if you try to assign anything else, Visual Basic generates a Type Mismatch error.
The MAPIMessages control also supports a RecipAddress property, which allows you to specify a recipient’s email address. But in the previous code fragment, I used the RecipDisplayName property instead. The reason is that MAPI requires all recipients of a message to go through address resolution, and it uses the display name for this purpose. Address resolution is the process of comparing an email address in string form to the recipients stored in the user’s address books. When a matching entry is found, the system associates the address book entry with the message. When the message ultimately is sent, the system reads critical information from the address book entry, such as the address, which transport provider to use, and whether to send to that address in Microsoft Exchange Rich Text Format (RTF). Again, this matching is based on the recipient’s display name, not his or her address.
If the value in RecipDisplayName is in a format that indicates that
it is itself a valid address, the system creates a temporary address
book entry to associate with the message, a so-called
one-off recipient. For example, strings of the
firstname.lastname@example.org are valid Simple Mail
Transport Protocol (SMTP) addresses, allowing you to write something
With MAPIMessages1 .SessionID = MAPISession1.SessionID .Compose .MsgSubject = "This is the subject." .MsgNoteText = "This is the message body." .RecipIndex = 0 .RecipDisplayName = "jsmith@FictitiousCompany.com" .Send End With
When the Send
method is called, MAPI attempts to resolve the name
jsmith@FictitiousCompany.com. During this
process, MAPI discovers that this is a valid format for SMTP email
addresses, so a one-off recipient is created and associated with the
message. Note that even if there is already an address book entry
with that address, that entry will not be matched during the address
resolution process. To match an existing entry, the display name must
If MAPI can’t resolve a name, or if the name resolves to more
than one address, the MAPIMessages control raises an error. If the
name can’t be resolved at all, the control raises a
mapUnknownRecipient error. In the case of
resolving to more than one name, the control raises a
You can force more sophisticated
behavior by explicitly calling the control’s ResolveName
method. This method resolves the name of the currently indexed
recipient only. (Again, the currently indexed recipient is defined by
the value of the MsgIndex and the RecipIndex properties.) If the
address is not found or is ambiguous, the control does one of two
things, depending on how you’ve set the
AddressResolveUI property. If this
property is set to
False, the control behaves as
described in the previous paragraph (i.e., it raises an error).
However, if the AddressResolveUI property is set to
True, the control triggers the address
book’s address resolution dialog box, allowing the user to
choose an appropriate address.
address resolution dialog box may contain a Cancel button which, if
pressed, causes a
mapUserAbort error to be raised
in your code. Be prepared to handle this error if you allow the
address resolution dialog box to be shown. Example 4-2 shows one way such an error handler could be
Example 4-2. Handling the mapUserAbort Error During Address Resolution
Private Sub Send( ) ' This procedure assumes that a message is being composed, that the ' recipients have already been set, and that all that needs to be done ' at this point is to resolve the recipient names and send the message. ' This procedure could be called in response to the user clicking a ' Send button on a form. Dim nRecip As Long On Error GoTo ErrorHandler For nRecip = 0 To MAPIMessages1.RecipCount - 1 MAPIMessages1.RecipIndex = nRecip MAPIMessages1.ResolveName Next nRecip MAPIMessages1.Send Exit Sub ErrorHandler: ' Did the user press Cancel on the address resolution dialog box? ' If so, just exit without sending the email. However, if a different ' error occurred, then re-raise that error so that it can be handled ' by the calling procedure. If Err.Number <> mapUserAbort Then Err.Raise Err.Number End If End Sub ' Send
If it’s successful, the ResolveName method uses the RecipDisplayName property and sets the RecipAddress property equal to the email address of the recipient. Further, if the recipient’s display name (as configured in the user’s address book) is different from or more complete than the name in RecipDisplayName, the ResolveName method sets RecipDisplayName to the name as it is stored in the address book.
' Delete current recipient. MAPIMessages1.Delete mapRecipientDelete
This statement deletes the recipient in the position defined by the RecipIndex property in the message defined by the MsgIndex property, and it decrements the indices of the recipients that followed the deleted recipient in the recipient set. It also decrements the RecipIndex property if the deleted recipient was the last one in the recipient set.
MAPI distinguishes between primary,
copy, and blind copy recipients. When you add recipients to your
outgoing message, they are flagged by default as primary. You can
change the type of a given recipient (which is defined, again, by the
value of the
RecipIndex property) by setting the
RecipType property. To set the current recipient to be a copy
recipient, set the RecipType property to
mapCcList. For a blind copy recipient, set the
RecipType property to
mapBccList. The default
mapToList. When messages are sent, the
receiving parties can see the primary and copy recipients but not the
blind copy recipients.
Calling the Send
method instructs MAPI to send the message to the mail server for
distribution. Note that the Send method does not set the MsgSent
True. That only happens when the
message has actually been moved to the mail server.
The Send method has an optional parameter that you’ll find
useful when you want to present the user with a standard message
composition dialog box. Rather than developing the dialog box
yourself, you can simply pass a value of
an argument to the Send method. This way, it takes only two lines of
code to allow the user to enter and send a standard email message:
MAPIMessages1.Compose MAPIMessages1.Send True
The resulting dialog box is shown in Figure 4-5.
If your code sets other properties prior to calling
True, those settings are
reflected in the dialog box shown to the user. For example, you may
wish to set a recipient and a subject programmatically, allowing the
user simply to enter the message text. However, while the dialog box
is shown, the user can make any changes he or she likes. If you need
total control over what the user enters, you’ll need to create
your own dialog box.
If the user cancels the dialog box, a
error is raised in your code. Your code should trap and handle this