发送邮件前压缩附件






4.33/5 (6投票s)
发送邮件前压缩附件
引言
首先,如果您想到的是 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_SENDNOTEMESSAGE
、EECONTEXT_SENDPOSTMESSAGE
和 EECONTEXT_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
- 自动化和扩展 MS Outlook.
- 白皮书:“Microsoft Outlook 和 Exchange 客户端扩展”.
- HOWTO:使用 VC++ 构建最小的 Exchange 客户端扩展.
- INFO:Exchange 客户端扩展基础知识.
- Outlook 扩展配置文件格式.