2010-07-26 53 views
6

我已經在Windows服務(C#)中編寫了一個組件,它負責發送大量的電子郵件。這些電子郵件將轉到許多域名上的收件人,其中包括真正的任何域名。 (是的,收件人需要電子郵件,不,我不是垃圾郵件。是的,我在與CAN-SPAM抱怨。是的,我知道sending email from code sucks。)許多電子郵件是事務性的到用戶操作);有些是批量(郵件合併基本上)。測試大批量SMTP電子郵件發送代碼的最佳方法是什麼?

我不想依賴外部SMTP服務器。 (其他考慮因素中,想要檢查郵箱中的退回郵件並嘗試解析郵件讓我感覺不好)。

我的設計非常簡單。事務消息和批量消息都會生成並插入到數據庫表中。此表格包含電子郵件信封和內容,以及嘗試計數和重試後的日期。

該服務運行一些工作線程,每次抓取20行並循環遍歷每個線程。使用Simple DNS Plus庫,我抓取收件人域的MX記錄,然後使用System.Net.Mail.SmtpClient同步發送電子郵件。如果撥打Send()成功,我可以將電子郵件出列。如果暫時失敗,我可以增加嘗試次數並設置適當的重試日期。如果它永久失敗,我可以出列並處理失敗。

顯然,將數千封測試郵件發送到數百個不同的實際域名是一個非常糟糕的想法。但是,我絕對需要對我的多線程發送代碼進行壓力測試。我也不太確定模擬SMTP的各種故障模式的最佳方式。另外,我想確保我能夠通過各種垃圾郵件控制方法(重名列出與網絡層最相關的東西)。

即使我最近發現我的ISP阻止連接到端口25的任意服務器,而不是我的ISP的SMTP服務器,我的小規模測試困難也加劇了。 (在生產中,這個東西當然會放在一個沒有阻塞端口25的服務器上,這並不能幫助我測試我的開發機器。)

所以,我最感興趣的兩件事情是:

  1. 我該如何去測試我的代碼?
  2. SmtpClient.Send()可能會失敗的各種方法是什麼?列出了六個例外; SmtpExceptionSmtpFailedRecipientsException似乎是最相關的。

更新:Marc B's answer指出,基本上,我創造我自己的SMTP服務器。他使我正在重新發明輪子的有效點,所以這裏是我的理由不使用「實際」一個(後綴,等等),而不是:

  1. 電子郵件有不同的發送優先級(雖然這是無關信封的X-Priority)。大量電子郵件是低優先級;事務性很高。 (並且任何電子郵件或一組電子郵件可進一步配置爲具有任意優先級。)我需要能夠暫停發送較低優先級的電子郵件,以便可以首先發送較高優先級的電子郵件。 (爲了達到這個目的,工作者線程每次獲得20個優先級隊列時,只需從隊列中選取最高優先級的項目。)

    如果我已經向外部SMTP服務器提交了幾千個大容量項目,那麼我現在無法將這些項目暫時擱置,而我現在要提交的項目已經發送。粗略的Google search顯示Postfix並不真正支持優先級; Sendmail優先考慮信封中的信息,這不符合我的需求。

  2. 我需要能夠向我的用戶顯示爆炸(一組批量電子郵件)的發送過程的進度。如果我只是把我所有的電子郵件都交給外部服務器,我不知道它在實際交付中有多遠。

  3. 因爲每個MTA的反彈信息都不同,所以我對解析反彈消息猶豫不決。 Sendmail的不同於Exchange的不同於[...]。另外,我會以什麼頻率檢查我的退回收件箱?如果退回消息本身未送達,該怎麼辦?

  4. 我並不太擔心爆炸中途中斷。

    如果我們在談論災難性故障(終止未處理的異常,斷電,無論什麼):由於工作線程在成功發送數據庫時從數據庫中取出每封郵件,我可以知道誰收到了爆炸,沒有。此外,當服務在失敗後重置時,它只會在隊列中停止的地方進行拾取。

    如果我們正在談論本地故障(一個SmtpException,DNS故障等):我只記錄失敗,增加電子郵件的嘗試計數器,然後再試。 (這基本上是SMTP規範要求的。)在嘗試之後,我可以永久性地使郵件失效(將郵件出列),並在稍後記錄失敗以供檢查。這樣,即使我的代碼第一次不是100%完美,我也可以發現奇怪的邊緣情況,即我的代碼無法處理–。 (老實說,這不會是)

  5. 我希望roll-my-own路由最終可以讓我比使用外部SMTP服務器更快地發送郵件。如果服務器不在我的控制範圍內,我不得不擔心限速問題;即使它是,它仍然是一個瓶頸。我使用的多線程體系結構意味着我要並行連接到多個遠程服務器,從而減少傳遞消息所需的總時間。

回答

2

假設您有兩臺服務器可用。一個將是發送者,一個將是接收者。您可以使用一系列假域來設置DNS(甚至只是主機文件)。就兩臺服務器而言,這些域是完全有效的,因爲本地DNS服務器對它們是權威的,但就網絡的其他部分而言,它們是完全無效的。只要確保解析器在DNS之前檢查主機文件即可。

一旦完成,您可以讓發送服務器將接收服務器垃圾郵件發送到您的內容,就像接收方做各種事情來測試您的代碼的反應一樣。灰名單,TCP延遲,硬反彈,ICMP不可達,ICMP跳數超過等等。

當然,由於您必須測試所有這些條件,您基本上都在創建自己的SMTP服務器,爲什麼不使用實際的一個開始?我猜測做一些基本的反彈消息解析所需的努力將遠遠小於不得不拿出代碼塊來處理所有postfix/sendmail/exim /等失敗模式......已經很好地處理了它們擁有。

當你認爲你的發送代碼必須從一開始就是完美的時候,尤其如此。如果電子郵件爆炸中途失敗並且收件人列表中只有一半收到郵件,那麼與數百或數千條郵件反彈時相比,您遇到的問題要大得多。或者更糟糕的是,以多種不同的方式失敗(某些服務器無法訪問,某些灰名單會導致流量過大等等)。反彈會愉快地坐在收到的隊列中,直到您手動處理它們,或修補反彈解析器來處理它們。

+0

我確實承擔了這種理解,實際上我確實創建了自己的SMTP服務器。我選擇了我自己的路線,原因是我添加到我的問題中。關於你答案的第二段:你能否擴展實際上做這些事情的方法? – josh3736 2010-07-26 08:05:28

+0

灰名單很容易。有各種大型SMTP服務器的插件可以做到這一點。硬反彈只是「在這個地址沒有這樣的用戶」類型的錯誤。在防火牆上可以模擬ICMP問題,在Linux中使用iptables尤其容易。 – 2010-07-26 15:32:10

0

searching around之後,我最終在我鋪設的幾臺額外的機器上燒起了Papercut。然後我使用測試地址*@[test-machine-*.local]填充我的數據庫。

雖然這確實工作得不錯,但我測試了25個發送線程,看起來好像我壓倒了運行Papercut的四臺電腦。幾百次發送嘗試遇到TCP連接失敗;這些消息被適當地重新發送(並且最終確實到達)。但是,在25,000封測試電子郵件中,大約500封簡單地消失了–在每臺測試機器的Papercut文件夾中添加* .eml文件只產生了24,500個。

現在我還想知道缺少的電子郵件是否是由於我的代碼中存在問題,或者Papercut是否刪除了它在SMTP中報告的郵件爲250 OK

相關問題