[研究][C#][ASP.NET] 加簽寄信(使用 MailKit 和 MimeKit)(二)
2022-06-09
********************************************************************************
相關數篇
[研究][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>
|
Default.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs"
Inherits="WebApplication1.Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
</head>
<body>
<form id="form1" runat="server">
Signed Email Test<br />
<asp:Button ID="Button_SendMail" runat="server" Text="Send"
OnClick="Button_SendMail_Click" /><br />
<asp:Label ID="Label1" runat="server"></asp:Label>
</form>
</body>
</html>
|
Default.aspx.cs
using System;
namespace WebApplication1
{
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button_SendMail_Click(object sender, EventArgs e)
{
string sendMailResult = CommonMailKit.SendSignedMailbyMailKit("主旨"
, "內容", "user123@abcdef.com.tw", "", "");
if (sendMailResult == "")
{
Label1.Text = "成功。";
}
else
{
Label1.Text = sendMailResult;
}
}
}
}
|
CommonMailKit.cs
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
using MimeKit.Cryptography;
using System;
using System.Configuration;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
namespace WebApplication1
{
public static class CommonMailKit
{
public static string SendSignedMailbyMailKit(
string emailSubject,
string emailContent,
string toAddress,
string ccAddress,
string bccAddress)
{
// http://www.mimekit.net/docs/html/Creating-Messages.htm
var message = new MimeMessage();
//message.From.Add(new MailboxAddress("contactus", "contactus@abcdef.com.tw"));
message.From.Add(new MailboxAddress("系統名稱", "SysName@abcdef.com.tw"));
if (toAddress != null)
message.To.Add(new MailboxAddress(toAddress, toAddress));
else
{
return "寄信失敗,收件者Email沒有設定。";
}
if (ccAddress != "")
message.Cc.Add(new MailboxAddress(ccAddress, ccAddress));
if (bccAddress != "")
message.Bcc.Add(new MailboxAddress(bccAddress, bccAddress));
message.ReplyTo.Add(new MailboxAddress("contactus", "contactus@abcdef.com.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
//"
// };
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];
// 抓 Web.Config 中設定的Email憑證序號,如果不保證抓到要用 object
//object setting = ConfigurationManager.AppSettings["EmailCertificateSN"];
//string emailCertificateSN = setting.ToString();
string emailCertificateSN = ConfigurationManager.AppSettings["EmailCertificateSN"];
//用 Email憑證序號抓比較不會抓錯
X509Certificate2 signCert =
store.Certificates.Find(X509FindType.FindBySerialNumber, emailCertificateSN, false)[0];
// X509Certificate2 signCert = store.Certificates.Find(X509FindType.FindByThumbprint, "12339f", false)[0];
// VS 2019 中正常,deploy 後執行,出現錯誤「機碼組不存在」
// 要用 MMC 設定 Email 憑證可讓 IIS_IUSRS 存取
CmsRecipient recipient = new CmsRecipient(signCert);
CmsRecipientCollection colle = new CmsRecipientCollection();
colle.Add(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);
//var signed = MultipartSigned.Create(ctx, signer, message.Body);
//var encrypted = ApplicationPkcs7Mime.Encrypt(ctx, colle, signed);
//message.Body = MultipartSigned.Create(ctx, signer, encrypted);
//message.Body = MultipartSigned.Create(ctx, signer, signed);
// MimeKit.Cryptography.CertificateNotFoundException
// A valid signing certificate could not be found.
//message.Body = MultipartSigned.Create(ctx, ctxsender, DigestAlgorithm.Sha1, message.Body);
}
// http://www.mimekit.net/docs/html/M_MailKit_Net_Smtp_SmtpClient__ctor.htm
using (var client = new SmtpClient())
{
// IIS SMTP 要設定 None,Auto 會失敗
// 來源 contactus@abcdef.com.tw 可用
//client.Connect("localhost", 25, SecureSocketOptions.None);
//client.Connect("localhost", 25, SecureSocketOptions.Auto);
//http://www.mimekit.net/docs/html/T_MailKit_Security_SecureSocketOptions.htm
//client.Connect("smtp.abcdef.com.tw", 25, false);// 非 SSL連線
//client.Connect("smtp.abcdef.com.tw", 25, SecureSocketOptions.Auto);// Auto SSL連線
client.Connect("smtp.abcdef.com.tw", 25, SecureSocketOptions.StartTlsWhenAvailable);// Auto SSL連線
//client.Connect("smtp.abcdef.com.tw", 465, SecureSocketOptions.Auto);
//client.Connect("smtp.abcdef.com.tw", 587, SecureSocketOptions.Auto);
client.Authenticate("帳號", "密碼");
//client.Authenticate("zzzz@gmail.com", "密碼");
try
{
//foreach (var message in messages)
//{
client.Send(message);
//}
client.Disconnect(true);
return ""; //成功
}
catch (Exception ex)
{
if (ex != null)
{
return ex.Message.ToString();
}
else
{
return "不明錯誤。";
}
}
}
}
}
}
|
上面實際測試可用,注意郵件憑證序號要換成自己的,至於附件可參考
http://www.mimekit.net/docs/html/Creating-Messages.htm
********************************************************************************
若考慮合併多種寄信元件,可能要避免使用 using 特定元件,因為某些物件在不同 mail 套件都有,程式會無法分辨,要強行指定,且別用 using,可改寫成如下
CommonMail.cs
//using MailKit.Net.Smtp;
//using MimeKit;
//using MimeKit.Cryptography;
using System;
using System.Linq;
namespace WebApplication1
{
public static class CommonMail
{
public static string SendSignedMailbyMailKit(
string emailSubject,
string emailContent,
string toAddress,
string ccAddress,
string bccAddress)
{
// http://www.mimekit.net/docs/html/Creating-Messages.htm
var message = new MimeKit.MimeMessage();
//message.From.Add(new MailboxAddress("SPM", "spm@abcdef.com.tw"));
message.From.Add(new MimeKit.MailboxAddress("系統名稱", "SysName@abcdef.com.tw"));
//message.To.Add(new MimeKit.MailboxAddress("User123", "user123@abcdef.com.tw"));
if (toAddress != null)
message.To.Add(new MimeKit.MailboxAddress(toAddress, toAddress));
else
{
return "寄信失敗,收件者Email沒有設定。";
}
if (ccAddress != "")
message.Cc.Add(new MimeKit.MailboxAddress(ccAddress, ccAddress));
if (bccAddress != "")
message.Bcc.Add(new MimeKit.MailboxAddress(bccAddress, bccAddress));
message.ReplyTo.Add(new MimeKit.MailboxAddress("contactus", "contactus@abcdef.com.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
//"
// };
message.Body = new MimeKit.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));
System.Security.Cryptography.X509Certificates.X509Store store =
new System.Security.Cryptography.X509Certificates.X509Store
("My", System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine);
store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadOnly
| System.Security.Cryptography.X509Certificates.OpenFlags.OpenExistingOnly);
//如果新舊憑證都尚未過期,會抓到舊的憑證
//X509Certificate2 signCert = store.Certificates.Find(X509FindType.FindBySubjectName, "憑證名稱", false)[0];
// 抓 Web.Config 中設定的Email憑證序號,如果不保證抓到要用 object
//object setting = ConfigurationManager.AppSettings["EmailCertificateSN"];
//string emailCertificateSN = setting.ToString();
string emailCertificateSN = System.Configuration.ConfigurationManager.AppSettings["EmailCertificateSN"];
//用 Email憑證序號抓比較不會抓錯
System.Security.Cryptography.X509Certificates.X509Certificate2 signCert =
store.Certificates.Find(System.Security.Cryptography.X509Certificates.X509FindType.FindBySerialNumber,
emailCertificateSN, false)[0];
// X509Certificate2 signCert = store.Certificates.Find(X509FindType.FindByThumbprint, "12339f33449f0cc767feb69e6dc2774ce10c1f60", false)[0];
// VS 2019 中正常,deploy 後執行,出現錯誤「機碼組不存在」
// 要用 MMC 設定 Email 憑證可讓 IIS_IUSRS 存取
//System.Security.Cryptography.Pkcs.CmsRecipient recipient =
// new System.Security.Cryptography.Pkcs.CmsRecipient(signCert);
MimeKit.Cryptography.CmsRecipient recipient =
new MimeKit.Cryptography.CmsRecipient(signCert);
//System.Security.Cryptography.Pkcs.CmsRecipientCollection colle =
// new System.Security.Cryptography.Pkcs.CmsRecipientCollection();
MimeKit.Cryptography.CmsRecipientCollection colle =
new MimeKit.Cryptography.CmsRecipientCollection();
colle.Add(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();
//System.Security.Cryptography.Pkcs.CmsSigner signer =
// new System.Security.Cryptography.Pkcs.CmsSigner(signCert);
MimeKit.Cryptography.CmsSigner signer =
new MimeKit.Cryptography.CmsSigner(signCert);
message.Body = MimeKit.Cryptography.MultipartSigned.Create(ctx, signer, message.Body);
//var signed = MultipartSigned.Create(ctx, signer, message.Body);
//var encrypted = ApplicationPkcs7Mime.Encrypt(ctx, colle, signed);
//message.Body = MultipartSigned.Create(ctx, signer, encrypted);
//message.Body = MultipartSigned.Create(ctx, signer, signed);
// MimeKit.Cryptography.CertificateNotFoundException
// A valid signing certificate could not be found.
//message.Body = MultipartSigned.Create(ctx, ctxsender, DigestAlgorithm.Sha1, message.Body);
}
// http://www.mimekit.net/docs/html/M_MailKit_Net_Smtp_SmtpClient__ctor.htm
using (var client = new MailKit.Net.Smtp.SmtpClient())
{
// IIS SMTP 要設定 None,Auto 會失敗
// 來源 contactus@abcdef.com.tw 可用
//client.Connect("localhost", 25, SecureSocketOptions.None);
//client.Connect("localhost", 25, SecureSocketOptions.Auto);
//client.Connect("smtp.abcdef.com.tw", 25, false);// 非 SSL連線,可用
client.Connect("smtp.abcdef.com.tw", 25, MailKit.Security.SecureSocketOptions.Auto);// Auto SSL連線,可用
//client.Connect("smtp.abcdef.com.tw", 465, SecureSocketOptions.Auto);// 無法連線,因為目標電腦拒絕連線。 210.241.25.196:465
//client.Connect("smtp.abcdef.com.tw", 587, SecureSocketOptions.Auto);// 無法連線,因為目標電腦拒絕連線。 210.241.25.196:465
client.Authenticate("寄信用帳號", "寄信用密碼");
//client.Authenticate("zzzz@gmail.com", "密碼");
try
{
//foreach (var message in messages)
//{
client.Send(message);
//}
client.Disconnect(true);
return "";
}
catch (Exception ex)
{
if (ex != null)
{
return ex.Message.ToString();
}
else
{
return "不明錯誤。";
}
}
}
}
}
}
|
(完)
相關
[研究][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
沒有留言:
張貼留言