解決 CDO 元件發信產生 CDO.Message.1 (0x80040220) 錯誤

  • 23717
  • 0
  • Memo
  • 2010-03-18

解決 CDO 元件發信產生 CDO.Message.1 (0x80040220) 錯誤

這問題其實是從這裡來的,不知怎麼的就一路追下去 (謎之音:因為太閒...)。完整錯誤訊息如下:

## ERROR

CDO.Message.1 錯誤 '80040220'
"SendUsing" (傳送使用) 設定值無效。

---

CDO.Message.1 (0x80040220)
The "SendUsing" configuration value is invalid.


最初找到的線索一:How to troubleshoot the "Could not create 'CDO.Message'" error message,以及線索二:adalf 的小技巧 - 啟用 IIS6 隔離模式對 CDO.Message 的影響,其中雖然有提到解法,但是必須修改原始程式碼,不符合原發問者需求…既然如此,通常大多數情況下會自己摸摸鼻子就此打住,畢竟回覆問題多半根據自己以往的經驗而來,若很幸運曾經處理過就順手提供參考做法,沒遇過的也許幫忙用錯誤訊息搜尋一下,看看可能有用的資料再回覆上去,就當是日行一善,解不解得還得看造化,實在沒理由花太多精神在上面。

這個案例是後者,我沒遇過類似問題,被打槍後心裡有點忿忿不平,本打算上去酸個兩句…不看還好,多看了幾次討論內容卻引起我的好奇心,總覺得似乎有某個環節遺漏了,因此我開始繼續搜尋資料,務必要把那 20 點分數拿下來想進一步釐清為何線索二的解法可行。

接著我注意到線索一有提到幾個狀況可能造成 CDO.Message 錯誤,其中之一是:
An invalid Simple Mail Transfer Protocol (SMTP) virtual server is being used, or the SmtpMail.SmtpServer property is incorrectly configured.

這跟線索二的解法似乎存在關連性:

objEmail.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
objEmail.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "localhost"
objEmail.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
objEmail.Configuration.Fields.Update

繼續追查下去發現,在 Windows Server 2003 作業系統上使用 CDOSYS.dll 發信,假如本機 SMTP 服務可用的情況下,sendusing 這一欄預設會是 1 (參考:CdoSendUsing Enum),這是 Pickup 模式,指的是以 IIS 預設執行帳戶透過本機 SMTP 服務發信,在這模式下 SMTP 服務會監控本機的 Inetpub\mailroot\pickup 資料夾 (預設是 C:\Inetpub\mailroot\Pickup),當有新郵件進來,SMTP 服務就會將它發送出去;另一種模式則是使用 SMTP Server 模式,也就是上述解法中 sendusing 這一欄指定為 2 的時候,此模式是利用 SMTP 通訊協定連線,因此在設定上必須搭配 smtpserver、smtpserverport 兩個欄位使用。

所以回到原發問者的問題,由於他變更了應用程式集區的身份識別帳戶,造成了利用 CDOSYS 元件發信失敗,以不更動程式碼為前提,只能選擇在 Pickup 模式下尋求解決之道。又因為預設帳戶使用上是沒問題的,所以可以推估若執行帳戶具有足夠的權限,應該是可以正常發送才對…反覆收集資料後,終於找到具體的方向,例如這一篇:Collaboration Data Objects for Windows 2000 (CDOSYS),於 Security Criteria 小節中的 Run-Time Permissions 就有指出:
When running an application that sends e-mail, the user will require either write access to the pick up directory, or read access to the IIS metabase, so the application can determine the SMTP port used for sending mail.

此時大致可以確定關鍵點如下:
  • 須具有對 Inetpub\mailroot\pickup 資料夾的寫入權限,否則無法存入新郵件到 pickup 資料夾。
  • 須具有讀取 IIS Metabase 的權限,寄送時才能正確取得相關設定資訊 (此模式下主要是要知道 pickup 資料夾路徑)。

幸運的是,在這一篇:System.Web.Mail FAQ 更追出了針對此一錯誤的 KB:Read access to the Everyone group is removed after you install Exchange 2000 SP3,裡面共寫了 4 種解決方式,我回覆給發問者照著 Workaround 1 的步驟跟著做,問題總算解決。

事後想想,這次解題過程中所收集到的資料還蠻有參考價值的,眼尖的人可能已經知道了,就是 .NET 1.1 時代的 System.Web.Mail 命名空間,其實也是利用 CDOSYS 元件來建構並傳送訊息,我猜就算時至今日,可能還有一部分的人還在使用也說不定…為了這理由,一定要發文紀錄一下的!