mapi java_使用 MAPI 实现邮件发送
使用 MAPI 實(shí)現(xiàn)郵件發(fā)送
原 作:deltacat
創(chuàng) 建:2004.09.16
最后更新:2004.11.01
版權(quán)聲明:作者保留版權(quán)。轉(zhuǎn)載時(shí)敬請(qǐng)保持文檔及說(shuō)明的完整性。
關(guān)鍵字: Visual C++ 郵件發(fā)送 Simple MAPI
一、問(wèn)題提出
我們經(jīng)常需要在自己的應(yīng)用程序中添加郵件支持,主要是發(fā)送郵件。目前,常用的方法有調(diào)用外部程序,直接對(duì)SMTP協(xié)議編程,或者使用 MAPI 接口。MAPI 是微軟提供的一套用于郵件收發(fā)的接口。打開 MSDN Library,你可以在 Messaging and Collaboration Services 下面找到它。
MAPI 使用比較復(fù)雜,于是微軟提供了幾個(gè)比較簡(jiǎn)單的解決方案,這里包括 CMC(Common Messaging Calls)和 Simple MAPI。
本文主要闡述使用 Simple MAPI 進(jìn)行開發(fā)一個(gè)簡(jiǎn)單的,用于發(fā)送一個(gè)帶附件的郵件的功能實(shí)現(xiàn)。文章后面有一小塊簡(jiǎn)單講述了使用完整 MAPI 的開發(fā),出于某些原因,并不推薦使用,如果需要更復(fù)雜的功能,我認(rèn)為還是老老實(shí)實(shí)封裝SMTP和POP3比較好。
二、Simple MAPI 介紹
Simple MAPI 包括一組很容易使用的函數(shù)以及相關(guān)的數(shù)據(jù)結(jié)構(gòu),可以在C/C++、VB等多種語(yǔ)言中使用。本文是基于VC設(shè)計(jì)的。
實(shí)現(xiàn)一個(gè)完整的郵件發(fā)送過(guò)程,實(shí)際上只需要一個(gè)函數(shù)“MAPISendMail()”,完整函數(shù)表及相關(guān)介紹參查閱MSDN Library->Platform SDK->Messaging and Collaboration Services。
MAPI 與郵件系統(tǒng)關(guān)系密切,要能夠使用MAPI的功能,系統(tǒng)必須安裝有支持 MAPI 的郵件系統(tǒng),比如Outlook、Outlook Express、Eudora、Netscape等. 在這里不得不提一下,使用非常廣泛的 FoxMail (5.0版本)似乎并不支持 MAPI,不過(guò)并沒有深入研究,如果有哪位高手發(fā)現(xiàn)實(shí)際上是支持的,麻煩告知我如何做。
Windows提供了一個(gè)文件 MAPI.H,包含所有的相關(guān)數(shù)據(jù)類型的定義。
三、功能的設(shè)計(jì)
我需要實(shí)現(xiàn)如下功能:可定制一封郵件,包括至少一個(gè)收件人,可選項(xiàng)目有標(biāo)題、正文、若干抄送人、密件抄送人、附件。能夠根據(jù)需要選擇自動(dòng)發(fā)送(無(wú)用戶干預(yù)),或彈出郵件編寫窗口。
為了便于使用和擴(kuò)展,我用了一個(gè)class來(lái)實(shí)現(xiàn)。
1、MAPI庫(kù)的初始化
包括兩個(gè)步驟:裝載MAPI庫(kù)、得到函數(shù)入口地址。
//-------------------------------------------------------------------------------------
m_hLibrary = ::LoadLibrary(_T("MAPI32.DLL"));
if(NULL == m_hLibrary)
{
return ::GetLastError();
}
// LPMAPISENDMAIL 等均定義在
m_lpfnMAPISendMail = (LPMAPISENDMAIL)::GetProcAddress(m_hLibrary, _T("MAPISendMail"));
// 可以根據(jù)需要添加其他函數(shù)入口。我的做法是用了一個(gè) InitMapi() 函數(shù),一次性將所有函數(shù)入口得出,作為類的成員變量保存。隨時(shí)可以使用
//-------------------------------------------------------------------------------------
2、發(fā)送郵件 MAPISendMail()
發(fā)送郵件功能就是對(duì)MAPISendMail()的封裝。下面解釋這個(gè)API函數(shù)的參數(shù)定義。
ULONG FAR PASCAL MAPISendMail(LHANDLE lhSession, ULONG ulUIParam, lpMapiMessage lpMessage, FLAGS flFlags, ULONG ulReserved);
ulUIParam 可以為 0,如果設(shè)置了 MAPI_DIALOG 標(biāo)志,則最好傳給它父窗口句柄。
lhSession和ulReserved這兩個(gè)參數(shù),簡(jiǎn)單地設(shè)置為0就可以了。
flFlags有三個(gè)有效位,分別是 MAPI_DIALOG,MAPI_LOGON_UI,MAPI_NEW_SESSION。如果希望程序彈出一個(gè)標(biāo)準(zhǔn)的郵件撰寫對(duì)話框,請(qǐng)?jiān)O(shè)置 MAPI_DIALOG,建議不要設(shè)置 MAPI_LOGON_UI 和 MAPI_NEW_SESSION。
重點(diǎn)是 lpMessage 這個(gè)參數(shù),它指向一個(gè)MapiMessage類型的結(jié)構(gòu),詳細(xì)地定義了一個(gè)郵件的全部信息。
3、結(jié)構(gòu) MapiMessage
使用時(shí)首先定義一個(gè)MapiMessage類型的變量,將其清零。現(xiàn)在我們只要簡(jiǎn)單地設(shè)定lpszSubject(標(biāo)題)、lpszNoteText(正文)、lpOriginator(發(fā)件人)、nRecipCount(收件人計(jì)數(shù),包含TO、CC、GCC),lpRecips(一個(gè)包含全部收件人的數(shù)組),nFileCount(附件計(jì)數(shù))、lpFiles(包含每個(gè)附件信息的數(shù)組)。
nRecipCount 和 nFileCount 的值一定要與實(shí)際的收件人和附件數(shù)目相符。
4、結(jié)構(gòu) MapiRecipDesc
必須設(shè)置 ulRecipClass、lpszName、lpszAddress
5、結(jié)構(gòu) MapiFileDesc
必須設(shè)置的有 lpszPathName、nPosiotion 兩個(gè)參數(shù)
這里有個(gè)地方需要特別注意。我在實(shí)際編碼過(guò)程中,有幾次 Outlook 不能正確彈出窗口(自動(dòng)發(fā)送也不行),但是同樣的過(guò)程,將郵件客戶設(shè)為 OutlookExpress 就沒有問(wèn)題。十分頭痛。經(jīng)過(guò)反復(fù)檢查,發(fā)現(xiàn) nPosiotion 這個(gè)參數(shù)十分重要。它指示附件在郵件中的位置。
對(duì)于一些郵件客戶端,比如OutlookExpress,也許忽略了這個(gè)參數(shù),由客戶端自動(dòng)安排。所以沒有問(wèn)題。對(duì)于另一些客戶端,比如Outlook,總是按照這個(gè)值的指示來(lái)安排的。如果附件數(shù)多于一個(gè),這個(gè)值如果相同,那么就會(huì)造成錯(cuò)誤。但是自行計(jì)算挺麻煩而且沒什么意義。解決的方法是,將其設(shè)為 -1,指示客戶軟件自行安排。:)
四、如何工作?
MAPISendMail() 會(huì)調(diào)用系統(tǒng)默認(rèn)的郵件客戶程序來(lái)發(fā)送郵件。對(duì)于彈出編輯窗的方式,它的行為和另一個(gè)函數(shù)? MAPISendDocuments() 差不多,但是可以定制標(biāo)題、收件人等等。而 MAPISendDocuments() 只是簡(jiǎn)單地準(zhǔn)備一個(gè)空白的郵件(包含附件),有關(guān) MAPISendDocuments() 的介紹參見 MSDN。
對(duì)于自動(dòng)發(fā)送。需要在 Outlook Express 的安全設(shè)置中,取消“當(dāng)有其他應(yīng)用程序試圖發(fā)送郵件時(shí)警告”這個(gè)選項(xiàng)。對(duì)于 Outlook,似乎使用 Simple MAPI 還沒有禁止安全警告的方法。
我設(shè)計(jì)的類包括三個(gè)接口函數(shù),Send(), AddFiles(), AddRecips(),其中只有 Send() 是必須的。使用時(shí)聲明一個(gè)對(duì)象,然后就直接調(diào)用 Send() 函數(shù)發(fā)送郵件。兩個(gè) Add 函數(shù)只要根據(jù)需要在 Send() 之前調(diào)用即可。
五、遺留問(wèn)題
我的開發(fā)環(huán)境是 Windows Xp Sp2 CHS,有如下幾個(gè)問(wèn)題,希望有高手可以解決。
1、自動(dòng)發(fā)送時(shí)的警告問(wèn)題。使用 Simple MAPI 能否解決?
2、默認(rèn)Outlook Express為系統(tǒng)郵件客戶端,可以立即發(fā)送,如果是Outlook,是先放到Outlook的發(fā)送隊(duì)列了,這時(shí)如果Outlook未運(yùn)行,就一直不會(huì)發(fā)送。怎樣可以保證無(wú)論郵件客戶軟件是否在運(yùn)行,我的程序都可以立即將郵件發(fā)送出去呢?
3、對(duì)于默認(rèn)是“Hotmail”的情況,只有以 @hotmail.com 結(jié)尾的帳號(hào)可以正常發(fā)送,而 @msn.com 的則不行。同時(shí),在發(fā)送時(shí),hotmail會(huì)將硬盤上的附件改名(末尾添加“^”符號(hào))并將文件屬性改為只讀,不過(guò)如果它正常上傳了附件,會(huì)將文件復(fù)原。
六、使用 MAPI
之所以使用 MAPI,起初是為了取得系統(tǒng)的地址本以及結(jié)局上面第五節(jié)的問(wèn)題2。
MAPI 相對(duì)于 Simple MAPI 要復(fù)雜的多。具體的使用方法可以參考 MSDN 文檔“Handling an Outgoing Message”、“Handling the Address Book”以及“Sending or Receiving a Message on Demand”。這里只對(duì)幾個(gè)關(guān)鍵的問(wèn)題加以說(shuō)明。
1、僅 Microsoft Outloook 比較好地支持了 MAPI,包括 Microsoft Outlook Express 均不支持 MAPI 調(diào)用。
2、MAPI 看似復(fù)雜,實(shí)際上,他的幾乎所有數(shù)據(jù)存儲(chǔ)和訪問(wèn),都是一個(gè)關(guān)鍵的接口:IMAPITable。也就是說(shuō),所有的數(shù)據(jù)存儲(chǔ)都是類似表的結(jié)構(gòu)。搞清楚了這個(gè),再編碼就很順了,不管是發(fā)送接收郵件還是操作地址本,存取數(shù)據(jù)流程都是搞表格。:P
3、上面的問(wèn)題2仍然不能解決。根據(jù)“Sending or Receiving a Message on Demand”的說(shuō)明,關(guān)鍵的是 FlushQueues() 函數(shù),但是我嘗試了各種方法,均無(wú)法使它生效。若干天對(duì)自己的痛苦反思之后,終于懷疑微軟有問(wèn)題。于是我在網(wǎng)上翻出了一篇問(wèn)答,中間有這么一段話:
“The IMAPIStatus::FlushQueues method appears not to work at all any more. Call it and you'll get a successful return code but nothing happens as a result. ” --Pete Maclean.
于是我徹底放棄。:(
七、結(jié)束語(yǔ)
本文是在給應(yīng)用程序中添加郵件發(fā)送功能的心得。過(guò)程中遇到了很多問(wèn)題,將他寫出來(lái),主要是給自己一個(gè)記錄,也是我第一次將自己的編程過(guò)程整理成文檔。
若本文還能幫到有同樣需要的朋友,會(huì)令我很開心。也希望有這方面經(jīng)驗(yàn)的朋友可以解決我的遺留問(wèn)題。
歡迎發(fā)送郵件至 catking@163.com 共同探討編程中的各種問(wèn)題,分享樂(lè)趣。
總結(jié)
以上是生活随笔為你收集整理的mapi java_使用 MAPI 实现邮件发送的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Geforce 错误代码 ERROR C
- 下一篇: 云酷科技UWB人员定位解决方案介绍