緊接着上一篇文章“WPF郵件群發工具開發 之 進度條(屬性改變通知機制)的實現”,這篇博文想把在工具開發中的實現要點跟大家交流、分享下,首先要說的是這個工具算是個Demo,實現的方法和功能都比較簡單,還有不少細節需要完善...
本文目錄:
如何隨機生成真實存在的QQ郵箱帳號?
經過測試,通過C#代碼發送郵件(調用SmtpClient類的Send方法,此方法無返回值,只會在發送郵箱賬戶錯誤或郵箱賬戶設置有問題,更多的是你用一個發送郵箱賬戶做群發,因為每種郵箱都有其這方面的限制,在連續很短時間內,只允許接收同一個郵箱發送的限量的郵件,如:QQ的限制大概50個左右),即使給一個根本不存在的郵箱里發送郵件,不會拋出異常,也更無法知道是否已發送成功,只能默認為發送成功,這樣一說,似乎隨機生成真實存在的QQ郵箱帳號是無法實現的事。——其實不然,可以用一個或幾個qq郵箱賬戶檢測生成的QQ郵箱是否真實存在! 代碼實現如下:
1 /// <summary> 2 /// 生成郵箱的事件處理 3 /// </summary> 4 /// <param name="sender"></param> 5 /// <param name="e"></param> 6 void btnGenerate_Email_Click(object sender, RoutedEventArgs e) 7 { 8 #region 判斷 9 string str = this.txtGenerateEmailCount.Text.Trim(); 10 if (string.IsNullOrEmpty(str)) 11 { 12 MessageBox.Show("請輸入要生成的郵箱個數!"); 13 return; 14 } 15 int generate_Email_Count = 0; 16 int.TryParse(str, out generate_Email_Count); 17 if (generate_Email_Count <= 0) 18 { 19 MessageBox.Show("郵箱個數必須為大於0!"); 20 return; 21 } 22 EmailAccount emailAccount = this._emailAccountList.Find(E => E.Smtp == "smtp.qq.com"); 23 if (emailAccount == null) 24 { 25 MessageBox.Show("qq郵箱賬戶不存在!"); 26 return; 27 } 28 #endregion 29 this._sendEmailsPropertyChanged.PropertyData += this.GetInfoTip("生成QQ郵箱"); 30 EmailInfoEntity emailInfoEntity = new EmailInfoEntity() 31 { 32 Title = this.txtEmailTitle.Text, 33 Body = this.txtEmailContent.Text, 34 DisplayName = this.txtDisplayName.Text.Trim(), 35 Attachment = _accessoriesFilePath, 36 Host = emailAccount.Smtp, 37 From = emailAccount.Email, 38 Pwd = emailAccount.Pwd 39 }; 40 #region 線程處理 41 this.StartSingleThreadWork(() => 42 { 43 int i = 0, num; 44 string email = string.Empty; 45 System.Random random = new Random(); 46 bool isSuc; 47 while (i < generate_Email_Count) 48 { 49 num = random.Next(123456, 987654321); 50 email = string.Format("{0}@qq.com", num); 51 if (this._emailList.Contains(email)) 52 continue; 53 emailInfoEntity.To = email; 54 isSuc = EmailHelper.SendEmail(emailInfoEntity); 55 Thread.Sleep(1000); 56 if (!isSuc) 57 { 58 _sendResult.SendFailEmails += string.Format("【{0}】:發送失敗!{1}", email, Environment.NewLine); 59 continue; 60 } 61 this._emailList.Add(email); 62 this._sendEmailsPropertyChanged.PropertyData += email + Environment.NewLine; 63 i++; 64 Console.WriteLine(email); 65 } 66 MessageBox.Show("Generate Over"); 67 }); 68 #endregion 69 }
單線程的使用及注意
1 /// <summary> 2 /// 開始一個單線程工作 3 /// </summary> 4 /// <param name="threadStartHandle"></param> 5 private void StartSingleThreadWork(ThreadStart threadStartHandle) 6 { 7 _thread = new Thread(() => 8 { 9 //禁用發送按鈕 10 _sendResult.SendControlIsEnabled = false; 11 threadStartHandle(); 12 //啟用發送按鈕 13 _sendResult.SendControlIsEnabled = true; 14 _thread.Abort(); 15 _thread = null; 16 Console.WriteLine(threadStartHandle.Method.Name);//---此行代碼不會執行,因為它位於 線程終止Abort方法之后,即Abort方法通知當前線程的使命已完成,其它的后續工作它將不會再執行! 17 }); 18 _thread.Start(); 19 }
除了上面代碼中的注釋說明,還有一點需要重點指出的是:.Net的公用語言運行時(CLR)能區分兩種不同類型的線程:前台線程和后台線程。這兩者的區別就是:應用程序必須運行完所有的前台線程才可以退出;而對於后台線程,應用程序則可以不考慮其是否已經運行完畢而直接退出,所有的后台線程在應用程序退出時都會自動結束。所以,當應用程序的窗體關閉時,你希望結束所有的線程,你可以把線程設置為后台線程,或在窗體關閉事件中檢查是否存在的執行中的線程並對其銷毀!
群發工具開發綜述
為了提高郵件發送的命中率,基於上面所提到的問題,應該采用多個郵箱賬戶輪發。
核心代碼如下:
1 void btnSend_Click(object sender, RoutedEventArgs e) 2 { 3 #region 判斷 4 if (this._emailList == null || this._emailList.Count == 0) 5 { 6 MessageBox.Show("當前要發送的郵箱為空!"); 7 return; 8 } 9 string eamilTitle = this.txtEmailTitle.Text.Trim(); 10 if (string.IsNullOrEmpty(eamilTitle)) 11 { 12 MessageBox.Show("請輸入email標題!"); 13 return; 14 } 15 string emailContent = this.txtEmailContent.Text.Trim(); 16 if (string.IsNullOrEmpty(emailContent)) 17 { 18 MessageBox.Show("請輸入email內容!"); 19 return; 20 } 21 if (!string.IsNullOrEmpty(_accessoriesFilePath)) 22 { 23 if (!System.IO.File.Exists(_accessoriesFilePath)) 24 { 25 MessageBox.Show("請確認所選附件是否存在!"); 26 return; 27 } 28 } 29 #endregion 30 string displayName = this.txtDisplayName.Text.Trim(); 31 int count = this._emailList.Count; 32 this.progressBar.Maximum = count; 33 #region 發送處理 34 this.StartSingleThreadWork(() => 35 { 36 Console.WriteLine("The send count is :" + count); 37 bool isSuc; 38 int failCount = 0, i = 1; 39 string failTip = string.Empty; 40 foreach (string email in this._emailList) 41 { 42 _sendResult.CurrentSendNum = i; 43 _sendResult.ProgressBarNumShow = i + "/" + count; 44 _sendCount = 0; 45 _sendAccountLastIndex = -1; 46 isSuc = SendEmail(new EmailInfoEntity() 47 { 48 DisplayName = displayName, 49 Body = emailContent, 50 Title = eamilTitle, 51 Attachment = _accessoriesFilePath, 52 To = email 53 }); 54 i++; 55 if (!isSuc) 56 { 57 failTip = string.Format("【{0}】:發送失敗!{1}", email, Environment.NewLine); 58 _sendResult.SendResultMes += failTip; 59 _sendResult.SendFailEmails += failTip; 60 failCount++; 61 } 62 System.Threading.Thread.Sleep(1000); 63 } 64 string tipStr = ("failCount is :" + failCount); 65 _sendResult.SendResultMes += tipStr; 66 MessageBox.Show(tipStr); 67 }); 68 #endregion 69 } 70 71 private bool SendEmail(EmailInfoEntity emailInfoEntity) 72 { 73 if (emailInfoEntity == null) 74 throw new ArgumentNullException("emailInfoEntity is Null"); 75 int sendAccountIndex = GetSendAccountIndex(); 76 EmailAccount emailAccount = _emailAccountList[sendAccountIndex]; 77 emailInfoEntity.Host = emailAccount.Smtp; 78 emailInfoEntity.From = emailAccount.Email; 79 emailInfoEntity.Pwd = emailAccount.Pwd; 80 bool isSuc = EmailHelper.SendEmail(emailInfoEntity); 81 _sendAccountLastIndex = sendAccountIndex; 82 _sendResult.SendResultMes += string.Format("★From:{0}★To:{1}★---isSuc:{2}!{3}", emailInfoEntity.From, emailInfoEntity.To, isSuc, Environment.NewLine); 83 _sendCount++; 84 if (!isSuc) 85 { 86 //如果發送失敗且已發送次數_sendCount小於_emailAccountListCount,則再次發送 87 if (_sendCount < _emailAccountListCount) 88 { 89 //當前線程掛起1s,再次發送 90 System.Threading.Thread.Sleep(1000); 91 return SendEmail(emailInfoEntity); 92 } 93 } 94 return isSuc; 95 } 96 97 /// <summary> 98 /// 獲得當前發送郵件的郵箱賬戶的index 99 /// </summary> 100 /// <returns></returns> 101 private int GetSendAccountIndex() 102 { 103 if (_emailAccountListCount > 1) 104 { 105 int sendAccountIndex = new Random().Next(_emailAccountListCount); 106 if (_sendAccountLastIndex >= 0 && sendAccountIndex == _sendAccountLastIndex) 107 return GetSendAccountIndex(); 108 return sendAccountIndex; 109 } 110 return 0; 111 }
工具運行效果圖如下:
好了,本文到此結束,希望有這么經驗或更好的建議的朋友,能夠多多交流!