Click here to Skip to main content
Click here to Skip to main content

Compressing attachments before sending the mail

, 29 Jul 2004
Rate this:
Please Sign up or sign in to vote.
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Karl Josefsson
Architect
Sweden Sweden
Been developing MAPI-modules (client-addins, gateways, agents, MTA's etc) since -96.
Works mainly in VC++, but when needed, looks at vb, asp, etc...
 
Always on the look for new things to do, got something for me? Smile | :)
I'm available for consulting, on a project-base or long-term development.

Comments and Discussions

 
QuestionI dont get any attachment info. Pinmemberwhtaperson19-Apr-07 23:19 
GeneralError message after the message is sent Pinmemberragsnp5-Nov-06 22:32 
Hi
Everything is working fine as per the document, thanks for the tutorial. But when I run this code after the message is sent I get "A program still has file attachment open" dialog. Microsoft says (http://support.microsoft.com/kb/158253) this is due to insufficient disk space.
I feel the file handle is not closed.
 
Any comments and suggestions ?
Questionnice, but does not compile with VS2003 OL2003 Pinmember*chopper*13-Jun-06 23:12 
AnswerRe: nice, but does not compile with VS2003 OL2003 Pinmemberragsnp6-Nov-06 2:07 
QuestionRe: nice, but does not compile with VS2003 OL2003 PinmemberAnushhPrabu10-Nov-06 2:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140814.1 | Last Updated 30 Jul 2004
Article Copyright 2004 by Karl Josefsson
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid