[研究][C#][ASP.NET] 自動加簽或不加簽寄信(使用 MailKit 和 MimeKit)(七)多收件者與單一附件(三)的改良
2023-02-20********************************************************************************
相關數篇
[研究][C#][ASP.NET] 自動加簽或不加簽寄信(使用 MailKit 和 MimeKit)(七)多收件者與單一附件(三)的改良
https://shaurong.blogspot.com/2023/02/caspnet-mailkit-mimekit.html
[研究][C#][ASP.NET] 自動加簽或不加簽寄信(使用 MailKit 和 MimeKit)(六)附件改良https://shaurong.blogspot.com/2023/01/caspnet-mailkit-mimekit.html
[研究][C#][ASP.NET] 自動加簽或不加簽寄信(使用 MailKit 和 MimeKit)(五)多收件者與多附件
[研究][C#][ASP.NET] 加簽寄信(使用 MailKit 和 MimeKit)(四)多收件者與多附件
https://shaurong.blogspot.com/2022/06/caspnet-mailkit-mimekit_13.html
[研究][C#][ASP.NET] 加簽寄信(使用 MailKit 和 MimeKit)(三)多收件者與單一附件
https://shaurong.blogspot.com/2022/06/caspnet-mailkit-mimekit_12.html
https://shaurong.blogspot.com/2022/06/caspnet-mailkit-mimekit_12.html
[研究][ASP.NET]加簽寄信-Windows Server 2019 IIS 10.0 抓 Key Store 中Email憑證所需的權限設定
[研究][C#][ASP.NET] 加簽寄信(使用 MailKit 和 MimeKit)(二)單一收件者、副本、密件
https://shaurong.blogspot.com/2022/06/caspnet-mailkit-mimekit.html
[研究][C#][ASP.NET] 加簽寄信 (使用 MailKit 和 MimeKit)
https://shaurong.blogspot.com/2019/10/caspnet-mailkit-mimekit_13.html
[研究][C#][ASP.NET] 寄信 (使用 MailKit 和 MimeKit)
https://shaurong.blogspot.com/2019/10/caspnet-mailkit-mimekit_11.html
[研究][C#][ASP.NET] 加簽寄信 (使用 System.Net.Mail.MailMessage)
https://shaurong.blogspot.com/2019/10/caspnet-systemnetmailmailmessage.html
mimekit - 在MimeKit上,簽名和加密
http://hant.ask.helplib.com/mimekit/post_4274560
MailKit Documentation - Creating messages
http://www.mimekit.net/docs/html/Creating-Messages.htm
有簡單寄信範例 (但沒有加簽)
MailKit Documentation - Digitally Signing Messages using S/MIME
http://www.mimekit.net/docs/html/Working-With-SMime.htm#Sign
.NET Framework 中過時的類型
https://docs.microsoft.com/zh-tw/dotnet/framework/whats-new/obsolete-types
System.Web.Mail.SmtpMail 過時,建議的替代做法是 System.Net.Mail.SmtpClient。
System.Net.Mail.SmtpClient
https://docs.microsoft.com/zh-tw/dotnet/api/system.net.mail.smtpclient?view=netframework-4.8
System.Net.Mail.SmtpClient 淘汰,建議改用 https://github.com/jstedfast/MailKit 和 https://github.com/jstedfast/MimeKit
GitHub - jstedfast/MailKit: A cross-platform .NET library for IMAP, POP3, and SMTP.
https://github.com/jstedfast/MailKit
GitHub - jstedfast/MimeKit: A .NET MIME creation and parser library with support for S/MIME, PGP, DKIM, TNEF and Unix mbox spools.
https://github.com/jstedfast/MimeKit
[研究][C#][ASP.NET] 加簽寄信 (使用 System.Net.Mail.MailMessage)
https://shaurong.blogspot.com/2019/10/caspnet-systemnetmailmailmessage.html
[研究][C#]加密加簽寄信(使用Cpi.Net.SecureMail)(一)
http://shaurong.blogspot.com/2017/02/ccpinetsecuremail.html
[研究][C#]加密加簽寄信(使用Cpi.Net.SecureMail)(二)
http://shaurong.blogspot.com/2017/02/ccpinetsecuremail_13.html
[研究][C#][ASP.NET] IIS SMTP 寄信失敗,拒絕存取路徑
https://shaurong.blogspot.com/2019/10/caspnet-iis-smtp.html
[研究] [ASP.NET] [C#] [WebForm] 寄信問題
http://shaurong.blogspot.com/2017/06/aspnet-c-webform.html
An S/MIME Library for Sending Signed and Encrypted E-mail
Pete Everett, 15 Jul 2010
https://www.codeproject.com/Articles/41727/An-S-MIME-Library-for-Sending-Signed-and-Encrypted
ASP.NET寄發加密加簽信件
https://www.nccst.nat.gov.tw/ArticlesDetail?lang=zh&seq=1160
Cpi.Net.SecureMail
https://www.codeproject.com/script/Content/ViewAssociatedFile.aspx?rzp=%2FKB%2Fsecurity%2FCPI_NET_SecureMail%2F%2FCpi.Net.SecureMail_src.zip&zep=Cpi.Net.SecureMail_src%2FCpi.Net.SecureMail%2FSecureMailMessage.cs&obid=41727&obtid=2&ovid=5
如何透過 .NET 送出一個包含 S/MIME 簽章的郵件
2009/06/06 21:20
https://blog.miniasp.com/post/2009/06/06/How-to-send-s-mime-email-using-net
https://shaurong.blogspot.com/2022/06/caspnet-mailkit-mimekit.html
[研究][C#][ASP.NET] 加簽寄信 (使用 MailKit 和 MimeKit)
https://shaurong.blogspot.com/2019/10/caspnet-mailkit-mimekit_13.html
[研究][C#][ASP.NET] 寄信 (使用 MailKit 和 MimeKit)
https://shaurong.blogspot.com/2019/10/caspnet-mailkit-mimekit_11.html
[研究][C#][ASP.NET] 加簽寄信 (使用 System.Net.Mail.MailMessage)
https://shaurong.blogspot.com/2019/10/caspnet-systemnetmailmailmessage.html
更新補充一些資訊,更新到 2021-11-29
********************************************************************************
[研究][ASP.NET]單一或多個 Email 格式驗證 (使用C#)
[研究]單一或多個 Email 格式驗證 (使用 HTML5)
********************************************************************************
環境:Visual Studio 2022 + ASP.NET + WebForm + Web Application + C#
先設定權限
[研究][ASP.NET]加簽寄信-Windows Server 2019 IIS 10.0 抓 Key Store 中Email憑證所需的權限設定https://shaurong.blogspot.com/2022/06/aspnet-windows-server-2019-iis-100-key.html
NuGet 要安裝 MailKit ( System.Data.SQLite 則不用),會自動安裝
Portable.BouncyCastle.1.9.0 System.Buffers.4.5.1 System.Numerics.Vectors.4.5.0 System.Runtime.CompilerServices.Unsafe.4.5.3 System.Memory.4.5.4 System.Text.Encoding.CodePages.4.5.1 MimeKit.3.2.0 System.Threading.Tasks.Extensions.4.5.4 MailKit.3.2.0 |
Web.Config 部分
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="EmailCertificateSN" value="郵件憑證序號" />
</appSettings>
</configuration>
|
CommonMailKit.cs
using MailKit.Net.Smtp; using MailKit.Security; using MimeKit; using MimeKit.Cryptography; using MimeKit.Utils; using System; using System.Collections.Generic; using System.Configuration; using System.IO; using System.Linq; using System.Security.Cryptography.X509Certificates; using System.Web; using System.Web.UI.WebControls; namespace NICSFrontWebApplication.App_Start { public class CommonMailKit { // 2023-02-20 成功,呼叫者要 MemoryStream,被呼叫是 Stream #region == public static string SendMail(string emailSubject, string emailContent, string toAddressList, string ccAddressList, string bccAddressList, string attacFileName, MemoryStream attacFileStream) == public static string SendMail(string emailSubject,string emailContent,string toAddressList,string ccAddressList,string bccAddressList, string attacFileName,Stream attacFileStream) { // http://www.mimekit.net/docs/html/Creating-Messages.htm var message = new MimeMessage(); //message.From.Add(new MailboxAddress("User123", "user123@mytest.idv.tw")); MimeKit.Cryptography.SecureMailboxAddress mailbox = new MimeKit.Cryptography.SecureMailboxAddress( System.Text.Encoding.GetEncoding("UTF-8"), "A公司", new List<string>(), "contactus@mytest.idv.tw", "" ); message.From.Add(mailbox); char[] stringSeparators = new char[] { ',', ';' }; if (toAddressList != null) { toAddressList.Replace(" ", "");//移除半形空白 InternetAddressList toList = new InternetAddressList(); foreach (var item in toAddressList.Split(stringSeparators, StringSplitOptions.RemoveEmptyEntries)) { // Invalid local-part at offset 0 // https://github.com/jstedfast/MailKit/issues/494 // toList.Add(new MailboxAddress(item, item)); var address = MailboxAddress.Parse(item); //address.Name = name; toList.Add(address); } message.To.AddRange(toList); } else { return "寄信失敗,收件者Email沒有設定。"; } // Cc 可以沒有 if (!string.IsNullOrEmpty(ccAddressList)) { ccAddressList.Replace(" ", "");//移除半形空白 InternetAddressList ccList = new InternetAddressList(); foreach (var item in ccAddressList.Split(stringSeparators, StringSplitOptions.RemoveEmptyEntries)) { var address = MailboxAddress.Parse(item); //address.Name = name; ccList.Add(address); } message.Cc.AddRange(ccList); } // Bcc 可以沒有 if (!string.IsNullOrEmpty(bccAddressList)) { bccAddressList.Replace(" ", "");//移除半形空白 InternetAddressList bccList = new InternetAddressList(); foreach (var item in bccAddressList.Split(stringSeparators, StringSplitOptions.RemoveEmptyEntries)) { var address = MailboxAddress.Parse(item); //address.Name = name; bccList.Add(address); } message.Bcc.AddRange(bccList); } // 預設回信收件者 //message.ReplyTo.Add(new MailboxAddress("User456", "user456@mytest.idv.tw")); //message.Subject = "Digitally Signing Email Test"; message.Subject = emailSubject; // message.Body = new MimeKit.TextPart("plain") // { // Text = @"Hey Alice, //What are you up to this weekend? Monica is throwing one of her parties on //Saturday and I was hoping you could make it. //Will you be my +1? //-- Joey //" // }; // http://www.mimekit.net/docs/html/Creating-Messages.htm var builder = new BodyBuilder { // Set the plain-text version of the message text // builder.TextBody = @"Hey Alice, //What are you up to this weekend? Monica is throwing one of her parties on //Saturday and I was hoping you could make it. //Will you be my +1? //-- Joey //"; // In order to reference selfie.jpg from the html text, we'll need to add it // to builder.LinkedResources and then use its Content-Id value in the img src. //var image = builder.LinkedResources.Add(@"C:\Users\Joey\Documents\Selfies\selfie.jpg"); //image.ContentId = MimeUtils.GenerateMessageId(); // Set the html version of the message text // builder.HtmlBody = string.Format(@"<p>Hey Alice,<br> //<p>What are you up to this weekend? Monica is throwing one of her parties on //Saturday and I was hoping you could make it.<br> //<p>Will you be my +1?<br> //<p>-- Joey<br> //<center><img src=""cid:{0}""></center>", image.ContentId); TextBody = emailContent }; // We may also want to attach a calendar event for Monica's party... // 下面測試可用 //builder.Attachments.Add(@"C:\Users\Administrator\Desktop\a.png"); //HttpFileCollection httpFileCollection = HttpContext.Current.Request.Files; //for (int i = 0; i < httpFileCollection.Count; i++) //{ // HttpPostedFile httpPostedFile = httpFileCollection[i]; // try // { // if (httpPostedFile.ContentLength > 0) // { // string filePath = httpPostedFile.FileName; // string filename = Path.GetFileName(filePath); // Stream fs = httpPostedFile.InputStream; // BinaryReader br = new BinaryReader(fs); // Byte[] bytes = br.ReadBytes((Int32)fs.Length); // MemoryStream destination = new MemoryStream(bytes); // builder.Attachments.Add(filename, destination); // } // } // catch (Exception ex) // { // if (ex == null) // { // return "不明錯誤。"; // } // else // return ex.Message; // } //} if (attacFileName != "") { // 建立 MIME 附件 MimePart attachment = new MimePart("application", "octet-stream") { Content = new MimeContent(attacFileStream), ContentDisposition = new ContentDisposition(ContentDisposition.Attachment), ContentTransferEncoding = ContentEncoding.Base64, FileName = attacFileName }; //builder.Attachments.Add(attacFileName, attacFileNameMemoryStream); builder.Attachments.Add(attachment); } // Now we just need to set the message body and we're done message.Body = builder.ToMessageBody(); //message.Body = new TextPart("plain") //{ // Text = emailContent //}; // http://www.mimekit.net/docs/html/Working-With-SMime.htm // Note: by registering our custom context it becomes the default S/MIME context // instantiated by MimeKit when methods such as Encrypt(), Decrypt(), Sign(), and // Verify() are used without an explicit context. //CryptographyContext.Register(typeof(MySecureMimeContext)); X509Store store = new X509Store("My", StoreLocation.LocalMachine); store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); //如果新舊憑證都尚未過期,會抓到舊的憑證 //X509Certificate2 signCert = store.Certificates.Find(X509FindType.FindBySubjectName, "憑證名稱", false)[0]; bool hasEmailCert = true; //從Web.Config中抓Email憑證序號值 string emailCertificateSN = ConfigurationManager.AppSettings["EmailCertificateSN"]; if (emailCertificateSN == null || emailCertificateSN == "") { //return "讀取不到Email憑證序號。"; hasEmailCert = false; } if (hasEmailCert == true) { //用 Email憑證序號抓比較不會抓錯 X509Certificate2 signCert = store.Certificates.Find(X509FindType.FindBySerialNumber, emailCertificateSN, false)[0]; if (signCert == null) { hasEmailCert = false; } //用指紋抓 // X509Certificate2 signCert = store.Certificates.Find(X509FindType.FindByThumbprint, "12339f33449f0cc767feb69e6dc2774ce10c1f60", false)[0]; // VS 2019 中正常,deploy 後執行,出現錯誤「機碼組不存在」 // 要用 MMC 設定 Email 憑證可讓 IIS_IUSRS 存取 CmsRecipient recipient = new CmsRecipient(signCert); CmsRecipientCollection colle = new CmsRecipientCollection { recipient }; using (var ctx = new MimeKit.Cryptography.TemporarySecureMimeContext()) { // Note: this assumes that the Sender address has an S/MIME signing certificate // and private key with an X.509 Subject Email identifier that matches the // sender's email address. var ctxsender = message.From.Mailboxes.FirstOrDefault(); CmsSigner signer = new CmsSigner(signCert); message.Body = MultipartSigned.Create(ctx, signer, message.Body); // MimeKit.Cryptography.CertificateNotFoundException // A valid signing certificate could not be found. //message.Body = MultipartSigned.Create(ctx, ctxsender, DigestAlgorithm.Sha1, message.Body); } } else { // No Email Cert // Nothing } // http://www.mimekit.net/docs/html/M_MailKit_Net_Smtp_SmtpClient__ctor.htm using (var client = new SmtpClient { ServerCertificateValidationCallback = (s, c, h, ee) => true }) { // IIS SMTP 要設定 None,Auto 會失敗 //client.Connect("localhost", 25, SecureSocketOptions.None); //http://www.mimekit.net/docs/html/T_MailKit_Security_SecureSocketOptions.htm //client.Connect("smtp.mytest.idv.tw", 25, false);// 非 SSL連線 //client.Connect("smtp.mytest.idv.tw", 25, SecureSocketOptions.Auto);// Auto SSL連線 //client.Connect("smtp.mytest.idv.tw", 465, SecureSocketOptions.Auto); //client.Connect("smtp.mytest.idv.tw", 587, SecureSocketOptions.Auto); // 某些 Mail Server (SMTP) 寄信惠要求帳號、密碼 // 某些 Mail Server (SMTP) 的帳號是完整含 @ 的Email,有些是 @ 之前的 //client.Authenticate("recontactus", "我的密碼"); //client.Authenticate("zzzz@gmail.com", "密碼"); // mail Server 驗證必須 bypass,必須有下面 Code // 否則會出現錯誤:根據驗證程序,遠端憑證是無效的。 // 目前把 ServerCertificateValidationCallback 加在上方 //MailKit.Net.Smtp.SmtpClient client = new MailKit.Net.Smtp.SmtpClient //{ // ServerCertificateValidationCallback = (s, c, h, ee) => true //}; string localIP = Common.GetLocalIPv4(); // 最短 localIP 為 1.2.3.4,長度7,Substring不可超過7 if (localIP.Substring(0, 5) == "10.3.") { message.Subject = message.Subject + " (" + localIP + ")"; // 非正式機加上 IP // OA LAN 上 Exchange Server // Email Cert 申請的是 contactus@mytest.idv.tw // Exchange Server Email : recontactus@mytest.idv.tw 一般帳號,寄信使用 // Exchange Server Email : contactus@mytest.idv.tw 群組帳號,無法寄信 // 真實寄信用 recontactus@mytest.idv.tw,但名義上的寄信者是 contactus@mytest.idv.tw // 為了和 Email Cert 的 contactus@mytest.idv.tw 相符合 //client.Connect("smtp.icst.org.tw", 25, false); // icst.org.tw 對外應該已宣稱無使用了 // IIS SMTP 要設定 None,Auto 會失敗 //client.Connect("smtp.mytest.idv.tw", 25, SecureSocketOptions.Auto); //client.Connect("smtp.mytest.idv.tw", 25, SecureSocketOptions.None); //client.Connect("smtp.mytest.idv.tw", 25, false); //client.Authenticate("recontactus", "我的密碼"); client.Connect("10.3.99.25", 25, false); client.Authenticate("setest", "123"); } if (localIP.Substring(0, 7) == "172.16.") { // IIS SMTP 要設定 None,Auto 會失敗 //client.Connect("172.16.3.25", 25, SecureSocketOptions.Auto); //client.Connect("smtp.mytest.idv.tw", 25, SecureSocketOptions.None); client.Connect("172.16.3.25", 25, false); client.Authenticate("contactus", "我的密碼"); } try { //foreach (var message in messages) //{ // Fortify SCA : Insecure SSL: Server Identity Verification Disabled client.Send(message); //} client.Disconnect(true); return ""; //成功 } catch (Exception) { throw; } } } #endregion } } |
Default.aspx.cs
protected void Button_Send_Click(object sender, EventArgs e) { Label_MSG1.Text = ""; Byte[] bytes = null; string filename = ""; MemoryStream memoryStream = null; if (FileUpload_Attachment.HasFile) { string filePath = FileUpload_Attachment.PostedFile.FileName; filename = Path.GetFileName(filePath); Stream fs = FileUpload_Attachment.PostedFile.InputStream; BinaryReader br = new BinaryReader(fs); bytes = br.ReadBytes((Int32)fs.Length); memoryStream = new MemoryStream(bytes); // http://www.mimekit.net/docs/html/P_MimeKit_BodyBuilder_Attachments.htm // builder.Attachments.Add (@"C:\Users\Joey\Documents\party.ics"); // https://csharp.hotexamples.com/examples/MimeKit/BodyBuilder/-/php-bodybuilder-class-examples.html // builder.Attachments.Add ("filename", new MemoryStream (Encoding.UTF8.GetBytes (text))); } // if (FileUpload_Attachment.HasFile) try { string emailReturn = CommonMailKit.SendMail(TextBox_Subject.Text, TextBox_Content.Text, TextBox_To.Text, TextBox_Cc.Text, TextBox_Bcc.Text, filename, memoryStream); Label_MSG1.ForeColor = System.Drawing.Color.Green; Label_MSG1.Text = DateTime.Now.ToString() + " 已送出郵件。"; Page.ClientScript.RegisterStartupScript(Page.GetType(), "message", "<script language='javascript' defer>alert('" + DateTime.Now.ToString() + " 已送出郵件。);</script>"); } catch (Exception) { throw; } } |
(完)
相關[研究][ASP.NET]加簽寄信-值不能為 null。參數名稱: findValue
mimekit - 在MimeKit上,簽名和加密
http://hant.ask.helplib.com/mimekit/post_4274560
MailKit Documentation - Creating messages
http://www.mimekit.net/docs/html/Creating-Messages.htm
有簡單寄信範例 (但沒有加簽)
MailKit Documentation - Digitally Signing Messages using S/MIME
http://www.mimekit.net/docs/html/Working-With-SMime.htm#Sign
.NET Framework 中過時的類型
https://docs.microsoft.com/zh-tw/dotnet/framework/whats-new/obsolete-types
System.Web.Mail.SmtpMail 過時,建議的替代做法是 System.Net.Mail.SmtpClient。
System.Net.Mail.SmtpClient
https://docs.microsoft.com/zh-tw/dotnet/api/system.net.mail.smtpclient?view=netframework-4.8
System.Net.Mail.SmtpClient 淘汰,建議改用 https://github.com/jstedfast/MailKit 和 https://github.com/jstedfast/MimeKit
GitHub - jstedfast/MailKit: A cross-platform .NET library for IMAP, POP3, and SMTP.
https://github.com/jstedfast/MailKit
GitHub - jstedfast/MimeKit: A .NET MIME creation and parser library with support for S/MIME, PGP, DKIM, TNEF and Unix mbox spools.
https://github.com/jstedfast/MimeKit
[研究][C#][ASP.NET] 加簽寄信 (使用 System.Net.Mail.MailMessage)
https://shaurong.blogspot.com/2019/10/caspnet-systemnetmailmailmessage.html
[研究][C#]加密加簽寄信(使用Cpi.Net.SecureMail)(一)
http://shaurong.blogspot.com/2017/02/ccpinetsecuremail.html
[研究][C#]加密加簽寄信(使用Cpi.Net.SecureMail)(二)
http://shaurong.blogspot.com/2017/02/ccpinetsecuremail_13.html
[研究][C#][ASP.NET] IIS SMTP 寄信失敗,拒絕存取路徑
https://shaurong.blogspot.com/2019/10/caspnet-iis-smtp.html
[研究] [ASP.NET] [C#] [WebForm] 寄信問題
http://shaurong.blogspot.com/2017/06/aspnet-c-webform.html
An S/MIME Library for Sending Signed and Encrypted E-mail
Pete Everett, 15 Jul 2010
https://www.codeproject.com/Articles/41727/An-S-MIME-Library-for-Sending-Signed-and-Encrypted
ASP.NET寄發加密加簽信件
https://www.nccst.nat.gov.tw/ArticlesDetail?lang=zh&seq=1160
Cpi.Net.SecureMail
https://www.codeproject.com/script/Content/ViewAssociatedFile.aspx?rzp=%2FKB%2Fsecurity%2FCPI_NET_SecureMail%2F%2FCpi.Net.SecureMail_src.zip&zep=Cpi.Net.SecureMail_src%2FCpi.Net.SecureMail%2FSecureMailMessage.cs&obid=41727&obtid=2&ovid=5
如何透過 .NET 送出一個包含 S/MIME 簽章的郵件
2009/06/06 21:20
https://blog.miniasp.com/post/2009/06/06/How-to-send-s-mime-email-using-net
沒有留言:
張貼留言