Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Compressing attachments before sending the mail

0.00/5 (No votes)
29 Jul 2004 1  
Compressing attachments before sending the mail

Introduction

First of all, if you are thinking Outlook Express, just forget it. The only three ways of integrating with Outlook Express are (and this is just me guessing) by paying Microsoft a lot of money and by giving them a really good reason to why you want to do that, or by hooking in through the encryption-entry, or by creating a proper hook and hacking your way in there. I've done the hacking (due to missing funds) and it's not a pretty sight, it works but it's everything from clean.

So, this is not for Outlook Express, this is only for Outlook from Office.

In this article, I will show you how to intercept a message before it is sent to compress the attachments.

Background

You need to at least know what a COM-interface is, and no, I'm not talking about that IDispatch-derived thing that VC generates for you when you create an ATL-project, I'm talking about proper COM, the old one... You will also need to know a bit about MAPI, you don't have to be a guru, but you should at least know what it's all about. If you don't know what you just read, don't worry, you'll get enough information so you know what you should search for.

It's a good idea if you read my previous article, Extending Outlook with new features, in which I explained the basics of MAPI and Outlook programming, also this article is based upon the project in that article.

Before I get going, when and if you want to debug your add-in, select Outlook.exe to be the executable in Dev-studio.

Intercepting the message...

Outlook exposes the interface IExchExtMessageEvents. This interface allows you to get notified when Outlook is about to submit a message to the selected transport, i.e., SMTP or Exchange. There are only two functions we are interested in, and these two together allows us to identify what is going to happen so that we can take the attachments and compress them before the message is submitted.

When the function OnSubmit gets called, we know that we are about to send a message, so the only thing we will do here is to set an internal flag indicating that we will send a message.

Outlook will then call the function OnWriteComplete. When this function gets called, the message has been written to the store and is ready to be sent, and this is where we will compress the attachments.

In order for us to be called here, we need to modify the function Install to allow us to be called for these events, and we do that by returning S_OK for these three contexts: EECONTEXT_SENDNOTEMESSAGE, EECONTEXT_SENDPOSTMESSAGE, and EECONTEXT_SENDRESENDMESSAGE.

Below is a part of the modified Install function:

STDMETHODIMP CMyAddin::Install(IExchExtCallback *lpExchangeCallback, 
                                        ULONG mcontext, ULONG ulFlags)
{
   AFX_MANAGE_STATE(AfxGetStaticModuleState());
   HRESULT hRet = S_FALSE;
   try
   {
      m_ulContext = mcontext;
      switch(m_ulContext)
      {
     :
    :
         case EECONTEXT_SENDNOTEMESSAGE:
         case EECONTEXT_SENDPOSTMESSAGE:
         case EECONTEXT_SENDRESENDMESSAGE:
            {
               hRet = S_OK;
            }
            break;

Then we will need to set the flag that tells us that we are about to send a message, and that is done in the function OnSubmit.

STDMETHODIMP COLTools::OnSubmit(IExchExtCallback *lpExchangeCallback)
{
   AFX_MANAGE_STATE(AfxGetStaticModuleState());
   // Set flag to indicate that we are about to send the message

   // this will be intercepted in the function OnWriteComplete where

   // we will compress the attachment(s)...

   m_bSubmittingMessage = TRUE;
   return S_FALSE;
}

Outlook will then call the function OnWriteComplete, and when that is done and thanks to the flag m_bSubmittingMessage, we know that we are about to send a message.

I've pasted parts of that function below, I've skipped some parts of the function to keep the length of the article down. But I'm sure you will understand what's going on in here:

STDMETHODIMP COLTools::OnWriteComplete(IExchExtCallback *lpExchangeCallback, 
                                                               ULONG ulFlags)
{
   AFX_MANAGE_STATE(AfxGetStaticModuleState());
   if (m_bSubmittingMessage)
   {
      try
      {
         char szTempFolder[MAX_PATH] = {0};
    GetTempPath(MAX_PATH, szTempFolder);
    :
    // Ask Outlook for the message

    if ((SUCCEEDED(lpExchangeCallback->GetObject(&lpMdb, 
                    (LPMAPIPROP *)&lpMessage)))&& (lpMessage))
    {
       CComPtr <IMAPITable>    pAttachTablePtr;
       // Get the table of attachments

       if (SUCCEEDED(hRet=lpMessage->GetAttachmentTable(0, 
                                          &pAttachTablePtr)))
       {
          // Enumerate all the attachments

          CSimpleArray<CAttachment*> cAttachments;
          :
          hRet = HrQueryAllRows(pAttachTablePtr, 
             (LPSPropTagArray)&tags, NULL, NULL, 0, &pRows);
          ULONG ulRowsMax = pRows->cRows;
          for (ULONG uldx=0;uldx<ulRowsMax;uldx++)
          {
        :
        // Open the attachment and store it in an array

        hRet = lpMessage->OpenAttach(ulAttachment, 
               &IID_IAttachment, MAPI_BEST_ACCESS, 
               &pAttachPtr);
        if (SUCCEEDED(hRet))
        {
           CAttachment *pAttachment = new CAttachment(pAttachPtr, 
                       ulMethod,FALSE, csFileName, csLongFileName);
           if (pAttachment)
           {
              pAttachment->SetAttachNum(ulAttachment);
              cAttachments.Add(pAttachment);
           }
        }
          }
          FreeProws(pRows);

          // Go through all the attachments and if the attachment is attached

          // by value, I.e. it's not a link to a fileserver,

          // nor an embedded object (message, image...)

          // then save the attachment to a file,

          // delete the attachment from the message,

          // zip the file and attach the zip-file

          // instead of the original file.

          for(int ndx=0;ndx<cAttachments.GetSize();ndx++)
          {
            CAttachment *pAttachment = cAttachments[ndx];
            if (pAttachment)
            {
              if (ATTACH_BY_VALUE==pAttachment->GetAttachMethod())
              {
                // Save the attachment to disk

                CString csFileName = szTempFolder;
                if (SUCCEEDED(pAttachment->SaveToFile(csFileName)))
                {
                  // Delete attachment from the message

                  if (SUCCEEDED(hRet = 
                     lpMessage->DeleteAttach(pAttachment->GetAttachNum(), 
                     NULL, NULL, 0)))
                  {
                    // Zip the file

                    if (SUCCEEDED(hRet = PackFile(csFileName)))
                    {
                     // Attach the zip-file

                     hRet = AttachFile(lpMessage, csFileName);
                     // Delete the zip-file

                     DeleteFile(csFileName.GetBuffer(0));
                    }
                  }
                }
              }
            delete pAttachment;
          }
       }
     }
    }
      }
      catch(...)
      {
      }
      // Reset the flag

      m_bSubmittingMessage = FALSE;
   }
   return S_FALSE;
}

As you can see, it's fairly straightforward, and if you look in the code, you will see that it's really not hard to do this.

The zip-code I used was submitted by ljw1004 in the article Zip Utils - clean, elegant, simple, C++/Win32.

Extending Outlook - links to other resources that can be of help

Now, these links are in no special order, so if you want to know more about how this works, then browse through these links.

Microsoft

Other

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here