[ASP.net / C#] .Net 完整的Mail寄信(Send Mail)功能 歡迎直接Copy Paste
讓我想到學生時代唸Training Kit Microsoft .NET Framework 2.0 應用程式開發基礎 Ⅱ時
裡頭有個郵件章節花了10~20幾頁講得很長,但重點只要記住MailMessage和SmtpClient這兩個物件就好了。
※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");
。