一個簡易郵件群發軟體設計與實現

来源:https://www.cnblogs.com/timeddd/archive/2019/08/01/11283183.html
-Advertisement-
Play Games

1 需求概述 指定一批郵箱地址,使用指定的郵箱發送指定的內容。 2 功能需求 配置文件配置用於發送的郵箱信息 郵件發送功能 日誌視窗輸出顯示 3 界面介面 郵件列表框 標題內容輸入框 發送按鈕 日誌輸出框 4 技術選型 .Net 4.0 C Winform 5 實現 5.1 新建項目 項目命名為 S ...


1 需求概述

指定一批郵箱地址,使用指定的郵箱發送指定的內容。

2 功能需求

  • 配置文件配置用於發送的郵箱信息
  • 郵件發送功能
  • 日誌視窗輸出顯示

3 界面介面

  • 郵件列表框
  • 標題內容輸入框
  • 發送按鈕
  • 日誌輸出框

4 技術選型

.Net 4.0 C# Winform

5 實現

5.1 新建項目

  • 項目命名為 SimpleEmailSender

5.2 在項目中添加配置文件

  • 配置發件郵箱信息
<configuration>
  <appSettings>
    <add key="email_stmp" value="smtp.****.com"/>
    <add key="send_user_email" value="****@****"/>
    <add key="send_user_pass" value="密碼"/>
    <add key="send_user_disp" value="發件人昵稱" />
  </appSettings>
</configuration>

5.3 製作界面

根據界面介面需求,界面佈局如下:

5.4 郵件發送輔助類

首先完成輔助類開發,最後再跟界面對接完成流程。
因為讀取了配置文件,需要添加 System.Configuration 程式集的引用。

定義 MailHelper 輔助類,讀取配置參數,向外提供發送郵件功能方法 SendMail。

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net.Mail;
using System.Text;

namespace SimpleEmailSender
{
    public class MailHelper
    {
        public static String EMAIL_USERNAME = ConfigurationManager.AppSettings["send_user_email"];
        public static String EMAIL_DISPNAME = ConfigurationManager.AppSettings["send_user_disp"];
        public static String EMAIL_PASSWORD = ConfigurationManager.AppSettings["send_user_pass"];
        public static String EMAIL_SMTP = ConfigurationManager.AppSettings["email_stmp"];
        public static ValidateResult SendMail(string email, string name, string content)
        {
            return SendMail("系統消息", email, name, content);
        }

        /// <summary>
        /// 發送郵件
        /// </summary>
        /// <param name="title">郵件標題</param>
        /// <param name="email">收件人地址</param>
        /// <param name="name">收件人名稱</param>
        /// <param name="content">郵件內容</param>
        public static ValidateResult SendMail(string title, string email, string name, string content)
        {
            MailAddress from = new MailAddress(EMAIL_USERNAME, EMAIL_DISPNAME); //郵件的發件人
            MailMessage mail = new MailMessage();
            //設置郵件的標題
            mail.Subject = title;

            //設置郵件的發件人
            //Pass:如果不想顯示自己的郵箱地址,這裡可以填符合mail格式的任意名稱,真正發mail的用戶不在這裡設定,這個僅僅只做顯示用
            mail.From = from;

            //設置郵件的收件人
            mail.To.Add(new MailAddress(email, name));

            //設置郵件的內容
            mail.Body = content;

            //設置郵件的格式
            mail.BodyEncoding = System.Text.Encoding.UTF8;
            mail.IsBodyHtml = true;
            //設置郵件的發送級別
            mail.Priority = MailPriority.Normal;

            mail.DeliveryNotificationOptions = DeliveryNotificationOptions.OnSuccess;

            SmtpClient client = new SmtpClient();
            //設置用於 SMTP 事務的主機的名稱,填IP地址也可以了
            client.Host = EMAIL_SMTP; 
            //設置用於 SMTP 事務的埠,預設的是 25
            client.Port = 25;
            client.UseDefaultCredentials = false;
            //這裡才是真正的郵箱登陸名和密碼
            client.Credentials = new System.Net.NetworkCredential(EMAIL_USERNAME, EMAIL_PASSWORD);
            client.DeliveryMethod = SmtpDeliveryMethod.Network;
            //都定義完了,正式發送了,很是簡單吧!


            ValidateResult vr = new ValidateResult(true, "發送成功!");
            try
            {
                client.Send(mail);
                return vr;
            }
            catch (Exception e)
            {
                vr.IsValid = false;
                vr.Message = e.Message;
                return vr;
            }
        }
    }

    public class ValidateResult
    {
        public bool IsValid { get; set; }
        public string Message { get; set; }

        public ValidateResult() {  
        }

        public ValidateResult(bool v, string m)
        {
            IsValid = v;
            Message = m;
        }
    }
}

5.5 清單解析

對於郵箱列表,使用正則表達式從文本框中匹配郵箱形成 List

        /// <summary>
        /// 提取郵件列表
        /// </summary>
        /// <param name="mails"></param>
        /// <returns></returns>
        private List<string> ParseEmailList(string mails)
        {
            List<string> list = new List<string>();
            var mc = Regex.Matches(mails, @"\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+", RegexOptions.IgnoreCase);

            foreach (Match c in mc)
            {
                list.Add(c.Value);
            }
            return list;
        }

5.6 日誌輸出方法準備

在日誌框中輸出內容,為了能線上程中調用,使用了 Invoke 方式執行。

/// <summary>
/// 日誌輸出支持線程中執行
/// </summary>
/// <param name="message"></param>
private void Log(string message)
{
    Invoke(new MethodInvoker(delegate
    {
        txtLog.AppendText(message + "\r\n");
    }));
}

5.7 線程發送

  • 發送方案設計

基本描述:給定郵箱列表,標題與內容,以線程方式執行發送,給出執行統計與狀態。
具體實現:使用線程池,但一組做為一個任務,全部完成才接收下一個任務,通過完成數量與郵箱列表長度的比較來判斷是否全部完成,信息通過日誌輸出的方式查看,形式上通過回調將日誌信息傳遞給調用者。

為此,這裡專門定義一個發送器,在應用中,定義一個實例來發起任務。儘管只定義一個實例,但這裡並不需要定義為設計模式中的單例模式,事實上,它是可以多實例運行。具體代碼說話!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace SimpleEmailSender
{
    public class EmailSender
    {
        #region 運行時數據
        // 郵箱列表
        private List<string> _EmailList = new List<string>();
        // 完成數量
        private volatile int _OverCount = 0;
        // 郵件標題
        private string _Title;
        // 郵件內容
        private string _Content;
        // 完成回調(主要是為了寫日誌)
        private Action<string> _Callback;
        #endregion

        /// <summary>
        /// 是否全部完成
        /// </summary>
        /// <returns></returns>
        public bool IsOver()
        {
            return _OverCount == _EmailList.Count;
        }

        /// <summary>
        /// 發起任務(如果不符合發起條件,則返回 false)
        /// </summary>
        /// <param name="emails"></param>
        /// <param name="title"></param>
        /// <param name="content"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public bool Send(List<string> emails, string title, string content, Action<string> callback)
        {
            if (!IsOver())
            {
                return false;
            }

            _EmailList = emails;
            _OverCount = 0;
            _Title = title;
            _Content = content;
            _Callback = callback;

            Start();
            return true;
        }

        /// <summary>
        /// 啟動任務
        /// 
        /// 以線程池方式運行,每個郵箱不論成敗完成數加1,並回調通知。
        /// </summary>
        private void Start()
        {
            foreach (string email in _EmailList)
            {
                var _email = email;
                ThreadPool.QueueUserWorkItem(t =>
                {
                    var vr = MailHelper.SendMail(_Title, _email, "", _Content);
                    _OverCount++;
                    _Callback(String.Format("進度[{3}/{4}] {0} 發送 {1},返回:{2}", _email, vr.IsValid ? "成功" : "失敗", vr.Message, _OverCount, _EmailList.Count));
                });
            }
        }


    }
}

5.8 按鈕事件

發送按鈕執行的流程為:如果之前的任務尚未完成,則等待。否則,首先提取郵箱列表,並格式化顯示,然後發起任務,觀察日誌即可。

        private EmailSender _Sender = new EmailSender(); 

        // 發送按鈕
        private void btnSend_Click(object sender, EventArgs e)
        {
            if (!_Sender.IsOver())
            {
                Log("之前的任務尚未完成,請等待完成!");
                return;
            }

            // 1. 提取郵件列表並格式化顯示
            string mails = txtEmailList.Text.Trim();
            var list = ParseEmailList(mails);
            // 2. 格式化顯示一下
            txtEmailList.Clear();
            foreach (var mail in list)
            {
                txtEmailList.AppendText(mail + "\r\n");
            }
            // 3. 發起任務
            var b = _Sender.Send(list, txtTitle.Text.Trim(), txtContent.Text, Log);
            Log(b ? "發起成功" : "發起失敗");
        }

6 運行結果

6.1 配置信息錯誤時

6.2 配置信息正確時

7 項目源代碼

https://github.com/triplestudio/SimpleEmailSender

歡迎訪問


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 人老了,玩不轉博客園的編輯器,詳細信息轉到:https://mp.weixin.qq.com/s/1r6YKBkyovQSMUgfm_VxBg 關鍵字:Github, NCC, Natasha,Roslyn, .NET Core2.0,.NET Core2.1,.NET Core2.2,.NET C ...
  • 問題 創建的項目提交到伺服器上,其他人下載項目後無法生成解決方案成功,無法自動生成dll,無法自動下載安裝相應的插件 解決方案 刪除packages文件夾即可,nuget就可以自動安裝相關的dll了 ...
  • 如上圖所示,一般這種問題都是dll版本和配置文件中的dll版本對應不上才引起的,可以通過替換對應版本的dll或者修改配置文件中的版本號即可。 然而我的情況是:修複後,還是不定時出現這樣的問題,我以為是被這個dll詛咒了,起初是真的沒啥辦法完全根治,出現問題後,只能覆蓋。 後來查看了下dll的屬性,原 ...
  • 1. 界面顯示 2.前端 jqgrid 代碼 //載入表格 function GetGrid() { var selectedRowIndex = 0; var $gridTable = $('#gridTable'); $gridTable.jqGrid({ url: "../../BaseMan ...
  • 1.界面顯示效果 2.資源下載 地址 1. jstree https://www.jstree.com/ 2.表格jqgrid https://blog.mn886.net/jqGrid/ 3.界面佈局 https://cloud.tencent.com/developer/section/1489 ...
  • 1.引用System.Media名稱空間下的類SoundPlayer SoundPlayer player = new SoundPlayer(); 2.方法調用Play(); public void Play() { player.SoundLocation = @".\x0pbk-swz4q.w ...
  • 現在圖片文字識別已經很成熟了,比如qq長按圖片,點擊圖片識別就可以識別圖片的文字,將不認識的、文字數量大的、或者不能賦值的值進行二次可複製功能。 我們現在就基於百度Ai開放平臺進行個人文字識別,demo使用的是C#控制台應用程式,後續有需要的可以嫁接到指定項目中使用,比如提供選擇圖片,點擊識別, 獲 ...
  • 小白的第一次使用: 程式員寫程式,就好比一個物品的慢慢誕生,我們今天的這個例子就可以想象成一個物品慢慢的在編譯的過程中,讓我們所看到 一、創建我們所測試的項目 1.創建一個簡單的帶有模型層(Model)和數據訪問層(DAL)的控制台應用程式架構。 DAL:數據訪問層,實現對資料庫的操作控制 Mode ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...