Click here to Skip to main content
12,948,130 members (69,612 online)
Click here to Skip to main content
Add your own
alternative version


30 bookmarked
Posted 29 Jul 2004

Compressing attachments before sending the mail

, 29 Jul 2004 CPOL
Rate this:
Please Sign up or sign in to vote.
Compressing attachments before sending the mail


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.


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)
      m_ulContext = mcontext;
               hRet = S_OK;

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)
   // 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)
   if (m_bSubmittingMessage)
         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, 
          // 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, 
        if (SUCCEEDED(hRet))
           CAttachment *pAttachment = new CAttachment(pAttachPtr, 
                       ulMethod,FALSE, csFileName, csLongFileName);
           if (pAttachment)

          // 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 = 
                     NULL, NULL, 0)))
                    // Zip the file
                    if (SUCCEEDED(hRet = PackFile(csFileName)))
                     // Attach the zip-file
                     hRet = AttachFile(lpMessage, csFileName);
                     // Delete the zip-file
            delete pAttachment;
      // 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.



  • <A title= href="" target=_blank>OOM Outlook 2000.
  • <A title= href="" target=_blank>OOM Outlook 98.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Karl Josefsson
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.

You may also be interested in...

Comments and Discussions

QuestionI dont get any attachment info. Pin
whtaperson19-Apr-07 23:19
memberwhtaperson19-Apr-07 23:19 
GeneralError message after the message is sent Pin
ragsnp5-Nov-06 22:32
memberragsnp5-Nov-06 22:32 
Questionnice, but does not compile with VS2003 OL2003 Pin
*chopper*13-Jun-06 23:12
member*chopper*13-Jun-06 23:12 
AnswerRe: nice, but does not compile with VS2003 OL2003 Pin
ragsnp6-Nov-06 2:07
memberragsnp6-Nov-06 2:07 
check out all the comments regarding link/compile errors in

else read the below extract
ok, solved my way out: I don't know why there is no problem with most of people though...

that's the way I solved this compilation/linking problem:

First, in Stdaxf.h, comment out
//#include <mapispi.h>

(mapispi.h reincludes mapiguid.h, I dont know why this is a problem since it should be protected by
#ifndef MAPIGUID_H
#define MAPIGUID_H

I think there is something fishy with INITGUID and precompiled headers and my version of VC6 SP5...)

anyway, with this, compilation is finally running, but then you have link errors!

to solve those, you basically have to redefine the DEFINE_GUID macroes, which seem to be corrupted by the INITGUID misbehaviour

in OutlookInterface.h, add the lines:

#ifndef INITGUID
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) EXTERN_C const GUID FAR name
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) EXTERN_C const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
#endif // INITGUID

just before this line:
DEFINE_GUID(IID_IOutlookExtCallback, 0x0006720d, 0x0000, 0x0000, 0xC0,0,0,0,0,0,0,0x46);

We have dealt with IID_IOutlookExtCallback, but there are two Exch symbols multiple-defined left, let's take care of them now

back in Stdafx.h, add #define NOEXCHEXTGUIDS just above the #include <exchext.h>
#include <mapiguid.h>
#include <exchext.h>

you know have unresolved externals

back in OutlookInterface.h, do the same trick as above and add:

#define DEFINE_EXCHEXTGUID(name, b) DEFINE_GUID(name, 0x00020D00 | (b), 0, 0, 0xC0,0,0,0,0,0,0,0x46)

DEFINE_EXCHEXTGUID(IID_IExchExtSessionEvents, 0x14);
DEFINE_EXCHEXTGUID(IID_IExchExtMessageEvents, 0x15);
DEFINE_EXCHEXTGUID(IID_IExchExtAttachedFileEvents, 0x16);
DEFINE_EXCHEXTGUID(IID_IExchExtPropertySheets, 0x17);
DEFINE_EXCHEXTGUID(IID_IExchExtAdvancedCriteria, 0x18);
DEFINE_EXCHEXTGUID(IID_IExchExtModelessCallback, 0x1a);


and voilà, all compiles and links successfully!

as to why I had to do all this... beats me! as I said, I suspect misbehaviour of INITGUID and the precompiled headers thingy. (I've tried not to use pch, but it then gets real ugly...)
QuestionRe: nice, but does not compile with VS2003 OL2003 Pin
AnushhPrabu10-Nov-06 2:34
memberAnushhPrabu10-Nov-06 2:34 

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

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

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.170524.1 | Last Updated 30 Jul 2004
Article Copyright 2004 by Karl Josefsson
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid