65.9K
CodeProject 正在变化。 阅读更多。
Home

发送邮件前压缩附件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (6投票s)

2004年7月30日

CPOL

3分钟阅读

viewsIcon

65329

downloadIcon

1022

发送邮件前压缩附件

引言

首先,如果您想到的是 Outlook Express,请直接忽略。与 Outlook Express 集成的唯一三种方法是(这只是我的猜测):支付微软一大笔钱,并给出他们非常充分的理由说明您为何要这样做;或者通过加密入口进行连接;或者创建一个适当的钩子并进行破解。我做过破解(由于资金不足),而且它一点也不优雅,它能工作,但绝不干净。

所以,这不是针对 Outlook Express 的,只针对 Office 中的 Outlook。

在本文中,我将向您展示如何在发送邮件之前拦截邮件,以压缩附件。

背景

您至少需要了解什么是 COM 接口,而且,我说的不是 VC 在创建 ATL 项目时为您生成的派生自 IDispatch 的那个东西,我说的是真正的 COM,那个旧的……您还需要了解一些 MAPI 的知识,不必成为专家,但至少应该知道它是什么。如果您不理解我刚刚读到的内容,别担心,您将获得足够的信息,以便知道应该搜索什么。

阅读我之前的文章 《使用新功能扩展 Outlook》 会很有帮助,在该文章中我解释了 MAPI 和 Outlook 编程的基础知识,本文也基于该文章的项目。

在我开始之前,当您想调试您的插件时,请在 DevStudio 中选择 Outlook.exe 作为要调试的可执行文件。

拦截邮件...

Outlook 暴露了 IExchExtMessageEvents 接口。该接口允许您在 Outlook 即将将邮件提交到选定的传输(例如 SMTP 或 Exchange)时收到通知。我们只对两个函数感兴趣,这两个函数合起来可以让我们识别将要发生的事情,以便在邮件提交之前提取附件并进行压缩。

当调用 OnSubmit 函数时,我们就知道即将发送一封邮件,因此我们在此处所做的唯一事情就是设置一个内部标志,指示我们将要发送一封邮件。

Outlook 随后将调用 OnWriteComplete 函数。当此函数被调用时,邮件已写入存储区并准备发送,这时我们将压缩附件。

为了让我们在此处被调用,我们需要修改 Install 函数,以便为这些事件注册回调,我们通过为这三个上下文返回 S_OK 来实现:EECONTEXT_SENDNOTEMESSAGEEECONTEXT_SENDPOSTMESSAGEEECONTEXT_SENDRESENDMESSAGE

下面是修改后的 Install 函数的一部分

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;

然后,我们需要设置一个标志,告知我们即将发送一封邮件,这在 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 随后将调用 OnWriteComplete 函数,当完成后,多亏了 m_bSubmittingMessage 标志,我们就知道我们即将发送一封邮件。

我已将该函数的一部分粘贴在下面,为了缩短文章长度,我省略了一些部分。但我相信您会理解其中的含义。

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;
}

正如您所见,这相当直接,如果您查看代码,您会发现实际操作并不难。

我使用的 zip 代码是 ljw1004 在文章 《Zip 工具 - 干净、优雅、简单、C++/Win32》 中提交的。

扩展 Outlook - 其他有用的资源链接

现在,这些链接没有特定顺序,所以如果您想了解更多关于其工作原理的信息,请浏览这些链接。

Microsoft

其他

发送邮件前压缩附件 - CodeProject - 代码之家
© . All rights reserved.