Image Map of Navigational Panel to Home / Contents / Search Distributing Application Updates

Transportation Issues

Image of line

The first issue, particularly with the Mail side, was that we couldn't simply attach our file to the mail message and send it off to the user who then would need to save the attachment to disk and import it. That was just fraught with danger. We needed the whole distribution to be invisible to the user.

Simple MAPI has two types of messages. These are IPC's and IPM's. IPM is what a normal mail message is. It is displayed inside Exchange and can be manipulated by the user. An IPC or Inter-Personal Communication, as opposed to Message, does not get displayed as part of exchange and is only accessible via program control.

This enabled our application at the client's site to periodically check for the existance of any IPC messages in the system and then to process them.

The code below demonstrates how to create an IPC message, Attach files to it, create a recipient list and send the message.

  ' Create an e-mail with the recipient list in it.
  MAPIMessages.Action = 6 ' Compose.
  MAPIMessages.MsgSubject = "GUI Distribution Item" ' Inform user.
  MAPIMessages.MsgIndex = -1
  MAPIMessages.MsgType = "IPC.GUI.DistributionItem" 
                                        ' Do not show in 'In Box'. 
    
  ' Set on error condition.  Only errors expected here are MAPI errors.
    On Error Resume Next
    
  ' Take all the recipient names and add them to the message.
  tmpID = ""
  RecipientIndex = 0

  ' Loop through all the recipients.
  For t = 1 To Len(RecipList)
    If Mid$(RecipList, t, 1) = ";" Or t = Len(RecipList) Then
      If t = Len(RecipList) Then
        tmpID = tmpID & Mid$(RecipList, t, 1)
      End If
      ' Create an index for this recipient.
      MAPIMessages.RecipIndex = RecipientIndex
      ' Add the name to the recipient list.
      MAPIMessages.RecipDisplayName = Trim$(tmpID)
      ' Resolve this recipients name.
      MAPIMessages.Action = 13
      ' Check for a known error
      If Err = 32014 Then 'Unknown MAPI recipient.
        ' Add the name to an array for later processing.
        ReDim Preserve FailedRecipients(UBound(FailedRecipients) + 1)
                       FailedRecipients(UBound
                                       (FailedRecipients)) = Trim$(tmpID)
        ' Delete the failed recipient.
        MAPIMessages.Delete (1)
      Else
        ' Set the type of recipient as 'To' rather than 'CC'.
        MAPIMessages.RecipType = 1
        ' Increment index count.
        RecipientIndex = RecipientIndex + 1
      End If
      tmpID = ""
    Else
      tmpID = tmpID & Mid$(RecipList, t, 1)
    End If
  Next t
    
  On Error GoTo ResolveMailRecipientsErr
    
  ' Attach the Distribution file to the mail message.
  MAPIMessages.AttachmentPosition = 0 ' First attachment.
  MAPIMessages.AttachmentType = 0 ' Data attachment.
  MAPIMessages.AttachmentPathName = App.Path & "\Distrib.MDB" 
                                        ' Attachment.

  ' Process the failed recipients and/or send the message.
  If UBound(FailedRecipients) > 0 Then
    ' Set up a message header.
    Msg = "The following Mail Recipient(s) failed to 
                    resolve;" & Chr$(10)& Chr$(13) & Chr$(10) & Chr$(13)
    ' Add all the failed recipients to the message.
    For t = 1 To UBound(FailedRecipients)
      Msg$ = Msg$ & Chr$(9) & t & ")  " & FailedRecipients(t) 
                  & Chr$(10) & Chr$(13)
    Next t
    ' Add a footer to the message.
    Msg$ = Msg$ & Chr$(10) & Chr$(13) & "Please check their properties 
                                                to resolve the problem."
    ' If we have recipients that resolved, 
    prompt to send without failures.
    If MAPIMessages.RecipCount > 0 Then
      er% = MsgBox(Msg$ & Chr$(10) & Chr$(13) & Chr$(10) & Chr$(13) 
                        & "Send mail distribution anyway?", 
                        vbExclamation + vbYesNo, "Mail Failure")
      If er% = vbYes Then
        ' Send the mail message at this point.
        MAPIMessages.Action = 3
      Else
        UserAction = MAPICancel
      End If
    End If
    ' Ask the user if they wish to go to the 
    Address book to resolve the failed recipients.
    er% = MsgBox(Msg$ & Chr$(10) & Chr$(13) & Chr$(10) 
                      & Chr$(13) & "View_ Address Book Now?", 
                      vbQuestion + vbYesNo, "Resolve Failure")
    If er% = vbYes Then
      Call frmAddressBook.SetupBook("Distribution List")
      frmAddressBook.txtName = FailedRecipients(1)
      frmAddressBook.Show 1
    End If
  Else
    MAPIMessages.Action = 3 ' No failures so send the message.
  End If

Granted, the first you look at this code, it's a little confusing. Actually, its damn confusing if you've never done this stuff before.

Basically the line;

  MAPIMessages.MsgType = "IPC.GUI.DistributionItem" 
                              ' Do not show in 'In Box'

actually creates the IPC message. Replacing the GUI and the DistributionItem allows you to customise the IPC so that you can determine at the other end, whether or not this message is one of yours. Don't forget that even Schedule + also uses IPC's - you don't want to go and start processing them. This also allows you to send several different types of communications for the same application.

Adding recipients requires you to supply the MAPI control with a semi-colon separated list of names. It's a real good idea to resolve each name in turn so that when an error occurs, you can process the bad recipient without having to unpick the recipient list again to see which one does not match.

The following lines;

  MAPIMessages.AttachmentPosition = 0 ' First attachment.
  MAPIMessages.AttachmentType = 0 ' Data attachment.
  MAPIMessages.AttachmentPathName = App.Path & "\Distrib.MDB" 
                              ' Attachment.

attach the file we want to distribute. Each attachment has its own position in the message and is zero based. Were this an IPM rather than an IPC, the order in which the user sees the attachments in the message is the order of the AttachmentPositon property.

Once you have the message built, you can send it. Exchange will then send the message next time it's scheduled to. Be aware that you will not be able to see the message in the outbox either. Again this is due to the fact that this message is an IPC.

One tip I will share with you is that when you are testing all this, make sure that you first set the message as an IPM so that you can see if the attachment is being attached properly, that the recipients appear and that the subject text, if any, is also there. There is nothing more impossible than debugging something you can't even see. Add that to the fact that if you did create an IPC, with an attachment (or not), then that IPC will get sent and sit in someone's in-box forever until you write a small application listing all the IPC's and removing them. This could make for some very large Exchange files clogging up the hard drive for no real reason. Bitter experience? Can you tell?

So, now that the message has been sent, you will want to pick it up at the other end yes? Look at the code below :

  ' Dim a few variables.
  Dim MessageID As String
    
  ' Find the first mail message.
  er = MAPIFindNext(gSession, 0, "IPC.GUI.DistributionItem", 
                    "",_ MAPI_UNREAD_ONLY, 0, MessageID)

  ' If Messages found then prompt user
  If er = SUCCESS_SUCCESS Then
    er = MsgBox("You have received new form versions in the mail. Upgrade 
                     now?", vbYesNo + vbQuestion, "Upgrade Forms")
    If er = vbYes Then Call ProcessMail
  End If

Looking for the message is as simple as looking for the IPC you created. You can, if you want, also check IPM's in the same way. Once the message has been identified, you will need to open it up, extract the files, mark as read and then, if required, delete it.

  Sub ProcessMail()
    
  ' Dim a few variables.
  Dim MessageID As String
  Dim Message As MapiMessage
  Dim Originator As MapiRecip
  Dim Recips() As MapiRecip
  Dim Files() As MapiFile
  Dim MailDB As Database
  
  ' Set a few entry level parameters.
    FileCounter = 1

  ' Get the first message that is a distribution message.
  er = MAPIFindNext(gSession, 0, "IPC.GUI.DistributionItem", 
                    "",_ MAPI_UNREAD_ONLY, 0, MessageID)

  ' While there are still messages to process.
  While er = SUCCESS_SUCCESS
    ' Read the mail item.
    er = MAPIReadMail(gSession, 0, MessageID, MAPI_UNREAD_ONLY, 
                      0,_ Message,  Originator, Recips(), Files())
    ' Process the files attached.
    For t = 0 To UBound(Files)
      FileCopy Files(t).PathName, App.Path & "\Distrib." & FileCounter
    Next t
    ' Delete the mail item.
    er = MAPIDeleteMail(gSession, 0, MessageID, 0, 0)
    ' Locate the next message in the message queue.
    er = MAPIFindNext(gSession, 0, "IPC.GUI.DistributionItem", 
                      "",_ MAPI_UNREAD_ONLY, 0, MessageID)
    ' Increment the file counter.
    FileCounter = FileCounter + 1
  Wend

By default, when you open a mail message, be it an IPM or an IPC, mail will save the attachments to a temporary directory and then remove them when the message is closed. The file names and paths are returned in the Files() array. In our application, we copy these files to our own directory, remove the IPC and then process the files. You could process the files directly from the temp directory to save you time and space.I just inherently don't trust temp directories.

That's primarily that. Yes, there is a some more you'll need to know, such as creating a session and some basic error handling. However, most of that is pretty well documented and should not create a great deal of pain.


Image of arrow to previous article Image of arrow to next article

Image of line

[HOME] [TABLE OF CONTENTS] [SEARCH]