[ASP.net / C#] .Net 完整的Mail寄信(Send Mail)功能 歡迎直接Copy Paste

[ASP.net / C#] .Net 完整的Mail寄信(Send Mail)功能 歡迎直接Copy Paste

讓我想到學生時代唸Training Kit Microsoft .NET Framework 2.0 應用程式開發基礎 Ⅱ

裡頭有個郵件章節花了10~20幾頁講得很長,但重點只要記住MailMessageSmtpClient這兩個物件就好了。

※2012.01.03追記論壇討論:上傳附件會Lock住檔案問題(解法為把Attachment和SmptClient 釋放掉)

※2012.01.04 修正程式,解決上傳附件被Lock問題

※2014-07-16 修正程式,釋放物件改用using語法,並使用for迴圈方式,走訪釋放每個上傳附件,避免檔案被Lock

※2018.3.5追記:如果想要收信者信箱出現寄信者名稱(非email),請見StackOverflow的討論:Sending emails in asp.net with specific name instead of sender email

※2018.6.24追記:發現使用MailMessage的To.Add()或CC.Add()加入多筆MailAddress,一次寄信給多個人,user收到信件時會看到彼此的Email Address(個資外洩XD)

已修正程式,全部都寄密件副本。

※2019.1.21追記:客戶反應,貌似使用密件副本寄信,Outlook會沒有收件者名稱,如果要修改的話,底下的 mms.Bcc.Add(),請自行改成 mms.To.Add()

但記得一次寄一封,信件裡可別出現其他用戶的Email導致個資外洩XD

 

 

 


        /// <summary>
        /// 寄信標題
        /// </summary>
        static string mailTitle = ConfigurationManager.AppSettings["mailTitle"].Trim();

        /// <summary>
        /// 寄信人Email
        /// </summary>
        static string sendMail = ConfigurationManager.AppSettings["sendMail"].Trim();
        /// <summary>
        /// 收信人Email(多筆用逗號隔開)
        /// </summary>
        static string receiveMails = ConfigurationManager.AppSettings["receiveMails"].Trim();

        /// <summary>
        /// 寄信smtp server
        /// </summary>
        static string smtpServer = ConfigurationManager.AppSettings["smtpServer"].Trim();

        /// <summary>
        /// 寄信smtp server的Port,預設25
        /// </summary>
        static int smtpPort = Convert.ToInt32(ConfigurationManager.AppSettings["smtpPort"].Trim());

        /// <summary>
        /// 寄信帳號
        /// </summary>
        static string mailAccount = ConfigurationManager.AppSettings["mailAccount"].Trim();

        /// <summary>
        /// 寄信密碼
        /// </summary>
        static string mailPwd = ConfigurationManager.AppSettings["mailPwd"].Trim();





    /// <summary>
    /// 完整的寄信功能
    /// </summary>
    /// <param name="MailFrom">寄信人E-mail Address</param>
    /// <param name="MailTos">收信人E-mail Address</param>
    /// <param name="Ccs">副本E-mail Address</param>
    /// <param name="MailSub">主旨</param>
    /// <param name="MailBody">信件內容</param>
    /// <param name="isBodyHtml">是否採用HTML格式</param>
    /// <param name="filePaths">附檔在WebServer檔案總管路徑</param>
    /// <param name="deleteFileAttachment">是否刪除在WebServer上的附件</param>
    /// <returns>是否成功</returns>
    public bool Mail_Send(string MailFrom, string[] MailTos, string MailSub, string MailBody, bool isBodyHtml, string[] filePaths,bool deleteFileAttachment)
    {



        try
        {
            //防呆
            if (string.IsNullOrEmpty(MailFrom))
            {//※有些公司的Mail Server會規定寄信人的Domain Name要是該Mail Server的Domain Name
                MailFrom = "sysadmin@system.com.tw";
            }

            //命名空間: System.Web.Mail已過時,http://msdn.microsoft.com/zh-tw/library/system.web.mail.mailmessage(v=vs.80).aspx
            //建立MailMessage物件
            System.Net.Mail.MailMessage mms = new System.Net.Mail.MailMessage();
            //指定一位寄信人MailAddress
            mms.From = new MailAddress(MailFrom);
            //信件主旨
            mms.Subject = MailSub;
            //信件內容
            mms.Body = MailBody;
            //信件內容 是否採用Html格式
            mms.IsBodyHtml = isBodyHtml;

            if (MailTos != null)//防呆
            {
                for (int i = 0; i < MailTos.Length; i++)
                {
                    //加入信件的收信人(們)address
                    if (!string.IsNullOrEmpty(MailTos[i].Trim()))
                    {
                        mms.Bcc.Add(new MailAddress(MailTos[i].Trim()));
                    }

                }
            }//End if (MailTos !=null)//防呆

        
            if (filePaths != null)//防呆
            {//有夾帶檔案
                for (int i = 0; i < filePaths.Length; i++)
                {
                    if (!string.IsNullOrEmpty(filePaths[i].Trim()))
                    {
                        Attachment file = new Attachment(filePaths[i].Trim());
                        //加入信件的夾帶檔案
                        mms.Attachments.Add(file);
                      
                    }

                }

            }//End if (filePaths!=null)//防呆

           using (SmtpClient client = new SmtpClient(smtpServer,smtpPort))//或公司、客戶的smtp_server
                    {
                        if (!string.IsNullOrEmpty(mailAccount) && !string.IsNullOrEmpty(mailPwd))//.config有帳密的話
                        {//寄信要不要帳密?眾說紛紜Orz,分享一下經驗談....

                            //網友阿尼尼:http://www.dotblogs.com.tw/kkc123/archive/2012/06/26/73076.aspx
                            //※公司內部不用認證,寄到外部信箱要特別認證 Account & Password

                            //自家公司MIS:
                            //※要看smtp server的設定呀~

                            //結論...
                            //※程式在客戶那邊執行的話,問客戶,程式在自家公司執行的話,問自家公司MIS,最準確XD
                            client.Credentials = new NetworkCredential(mailAccount, mailPwd);//寄信帳密
                        }
                        client.Send(mms);//寄出一封信
                    }//end using 
                    //釋放每個附件,才不會Lock住
                    if (mms.Attachments != null && mms.Attachments.Count>0)
                    {
                        for (int i = 0; i < mms.Attachments.Count;i++ )
                        {
                            mms.Attachments[i].Dispose();
                           
                        } 
                    }
            #endregion 

            #region 要刪除附檔
            if (deleteFileAttachment && filePaths != null && filePaths.Length>0)
            {

                foreach (string filePath in filePaths)
                {
                    File.Delete(filePath.Trim());
                }

            }
            #endregion 


            return true;//成功
        }
        catch (Exception ex)
        {
            return false;//寄失敗
        }
    }

 

 

呼叫方法:


//Button Click事件
protected void btn_Insert_Click(object sender, EventArgs e)
    {
        if (fu_upload.HasFile)//FileUpload控制項有選擇檔案
        {
            //先上傳檔案
            fu_upload.SaveAs(Server.MapPath("~/upload/") + fu_upload.FileName);
        }

        List<string> listFile = new List<string>();
        listFile.Add(Server.MapPath("~/upload/") + fu_upload.FileName);
        this.Mail_Send(sendMail, new string[]{"shadow@hotmail.com"},  mailTitle , "內文", true,listFile.ToArray(),true);
         
    }

 

2014.07.16 上述方法,在寄信時會把附件檔案丟到Server上,日久可能減少硬碟空間

以下追記一個把附件存入Stream的方法,這樣就不會增加硬碟空間使用量,請自行依需求決定,有的專案需要把寄信時的附件檔也保存到Server上當備份↓


#region 寄信相關
        /// <summary>
        /// 寄信標題
        /// </summary>
        static string mailTitle = ConfigurationManager.AppSettings["mailTitle"].Trim();

        /// <summary>
        /// 寄信人Email
        /// </summary>
        static string sendMail = ConfigurationManager.AppSettings["sendMail"].Trim();
        /// <summary>
        /// 收信人Email(多筆用逗號隔開)
        /// </summary>
        static string receiveMails = ConfigurationManager.AppSettings["receiveMails"].Trim();

        /// <summary>
        /// 寄信smtp server
        /// </summary>
        static string smtpServer = ConfigurationManager.AppSettings["smtpServer"].Trim();

        /// <summary>
        /// 寄信smtp server的Port,預設25
        /// </summary>
        static int smtpPort = Convert.ToInt32(ConfigurationManager.AppSettings["smtpPort"].Trim());

        /// <summary>
        /// 寄信帳號
        /// </summary>
        static string mailAccount = ConfigurationManager.AppSettings["mailAccount"].Trim();

        /// <summary>
        /// 寄信密碼
        /// </summary>
        static string mailPwd = ConfigurationManager.AppSettings["mailPwd"].Trim();




        /// <summary>
        /// 完整的寄信函數
        /// </summary>
        /// <param name="MailFrom">寄信人Email Address</param>
        /// <param name="MailTos">收信人Email Address</param>
        /// <param name="Ccs">副本Email Address</param>
        /// <param name="MailSub">主旨</param>
        /// <param name="MailBody">內文</param>
        /// <param name="isBodyHtml">是否為Html格式</param>
        /// <param name="files">要夾帶的附檔</param>
        /// <returns>回傳寄信是否成功(true:成功,false:失敗)</returns>
        public  bool Mail_Send(string MailFrom, string[] MailTos, string MailSub, string MailBody, bool isBodyHtml, Dictionary<string, Stream> files)
        {
             
            try
            {
                //沒給寄信人mail address
                if (string.IsNullOrEmpty(MailFrom))
                {//※有些公司的Smtp Server會規定寄信人的Domain Name須是該Smtp Server的Domain Name,例如底下的 system.com.tw
                    MailFrom = "sysadmin@system.com.tw";
                }

                //命名空間: System.Web.Mail已過時,http://msdn.microsoft.com/zh-tw/library/system.web.mail.mailmessage(v=vs.80).aspx
                //建立MailMessage物件
                 MailMessage mms = new  MailMessage();
                //指定一位寄信人MailAddress
                mms.From = new MailAddress(MailFrom);
                //信件主旨
                mms.Subject = MailSub;
                //信件內容
                mms.Body = MailBody;
                //信件內容 是否採用Html格式
                mms.IsBodyHtml = isBodyHtml;

                if (MailTos != null)//防呆
                {
                    for (int i = 0; i < MailTos.Length; i++)
                    {
                        //加入信件的收信人(們)address
                        if (!string.IsNullOrEmpty(MailTos[i].Trim()))
                        {
                            mms.Bcc.Add(new MailAddress(MailTos[i].Trim()));
                        }

                    }
                }//End if (MailTos !=null)//防呆

       


                     //附件處理
                    if (files != null && files.Count > 0)//寄信時有夾帶附檔
                    {
                        foreach (string fileName in files.Keys)
                        {
                            Attachment attfile = new Attachment(files[fileName], fileName);
                            mms.Attachments.Add(attfile);
                        }//end foreach
                    }//end if 

                    using (SmtpClient client = new SmtpClient(smtpServer,smtpPort))//或公司、客戶的smtp_server
                    {
                        if (!string.IsNullOrEmpty(mailAccount) && !string.IsNullOrEmpty(mailPwd))//.config有帳密的話
                        {//寄信要不要帳密?眾說紛紜Orz,分享一下經驗談....

                            //網友阿尼尼:http://www.dotblogs.com.tw/kkc123/archive/2012/06/26/73076.aspx
                            //※公司內部不用認證,寄到外部信箱要特別認證 Account & Password

                            //自家公司MIS:
                            //※要看smtp server的設定呀~

                            //結論...
                            //※程式在客戶那邊執行的話,問客戶,程式在自家公司執行的話,問自家公司MIS,最準確XD
                            client.Credentials = new NetworkCredential(mailAccount, mailPwd);//寄信帳密
                        }
                        client.Send(mms);//寄出一封信
                    }//end using 
                    //釋放每個附件,才不會Lock住
                    if (mms.Attachments != null && mms.Attachments.Count>0)
                    {
                        for (int i = 0; i < mms.Attachments.Count;i++ )
                        {
                            mms.Attachments[i].Dispose();
                            
                        } 
                    }
                 
                return true;//成功
            }
            catch (Exception ex)
            {
                //寄信失敗,寫Log文字檔
                NLog.LogManager.GetCurrentClassLogger().ErrorException("寄信失敗", ex);
                return false;
            }
        }//End 寄信
        #endregion

至於.config檔裡的內容(應用程式的App.config或網站的Web.config)


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    
    <!--寄信的標題-->
    <add key="mailTitle" value="輸入一個信件主旨"/>
    <!--寄信人Email-->
    <add key="sendMail" value="program_By_Shadow@system.com"/>
    <!--收信人Email(多筆用逗號隔開)-->
    <add key="receiveMails" value="Sample@hotmail.com,shadow@test.com"/>
    
    <!--請注意,程式執行寄信時,使用的線路是中華電信的線路,才能用msa.hinet.net-->
    <!--寄信smtp server-->
    <add key="smtpServer" value="msa.hinet.net"/>
    <!--寄信smtp server的Port,預設25-->
    <add key="smtpPort" value="25"/>
    <!--寄信帳密-->
    <add key="mailAccount" value=""/>
    <add key="mailPwd" value=""/>
  </appSettings>
   
</configuration>

↑使用方法


//Button Click事件
protected void btn_Insert_Click(object sender, EventArgs e)
    {

        Dictionary<string,Stream> listStream = new Dictionary<string,Stream>();
        if (fu_upload.HasFile)//有選擇檔案
        {
            //加入檔名和檔案Stream
            listStream.Add(fu_upload.FileName,fu_upload.FileContent);
            //使用以下的方法也可以
            //listStream.Add(fu_upload.FileName,fu_upload.PostedFile.InputStream);
        }

        this.Mail_Send(sendMail ,new string[]{"shadow@hotmail.com"},  mailTitle , "內文", true, listStream);

         
    }

※2018.6.24 追記非同步寄信的範例程式碼

public class MailUtility
{
        
        #region 寄信相關

        /// <summary>
        /// 寄信smtp server
        /// </summary>
        public static readonly string smtpServer = ConfigurationManager.AppSettings["smtpServer"];
 
        //必填sender
        /// <summary>
        /// 寄信帳號
        /// </summary>
        public static readonly string MailFrom = ConfigurationManager.AppSettings["mailAccount"];


        /// <summary>
        /// 寄信函數
        /// </summary>
        /// <param name="MailTos">收信人Email Address</param>
        public static void Mail_SendAsync(string[] MailTos, string MailSub, string MailBody)
        {
            Task.Run(async ()=> 
            { 
                //建立MailMessage物件
                MailMessage mms = new MailMessage()
                {
                    //指定一位寄信人MailAddress
                    From = new MailAddress(MailFrom, "電子報發信系統"),
                    //信件主旨
                    Subject = MailSub,
                    SubjectEncoding = Encoding.UTF8,
                    //信件內容
                    Body = MailBody,
                    BodyEncoding = Encoding.UTF8,
                    //信件內容 是否採用Html格式
                    IsBodyHtml = true
                };
                if (MailTos!=null)
                {
                    foreach (string mailAddress in MailTos)
                    {
                        //信件的收信人(們)address
                        mms.Bcc.Add(new MailAddress(mailAddress));
                    }
                }
                  
                try
                {
                    using (SmtpClient client = new SmtpClient(smtpServer, port: 25))//或公司、客戶的smtp_server
                    {
                        //.net 4.5才有的 SendMailAsync 方法
                        await client.SendMailAsync(mms);//寄出一封信
                        //避免附件被Lock無法異動
                        if (mms.Attachments!=null && mms.Attachments.Count>0)
                        {
                            mms.Attachments.Dispose();
                        }
                        mms.Dispose();
                    }//end using  
                }
                catch (Exception ex)
                {
                    //寄信失敗,寫Log文字檔 
                    ex.ToString();
                }
            });
             
        }//End 寄信
        #endregion

        


    }

使用方式↓

   //寄一封信
    MailUtility.Mail_SendAsync(new string[] { "shado@hotmail.com" } ,"subject", "mailbody");