顯示具有 MailKit 標籤的文章。 顯示所有文章
顯示具有 MailKit 標籤的文章。 顯示所有文章

2025年10月17日 星期五

[研究]System.Net.Mail.MailMessage 寄信成功,MailKit 出現 "5.7.60 SMTP; Client does not have permissions to send as this sender"

[研究]System.Net.Mail.MailMessage 寄信成功,MailKit 出現 "5.7.60 SMTP; Client does not have permissions to send as this sender"

2025-10-17

環境:Visual Studio 2022 + ASP.NET + WebForm + Web Application + C# + SQL Server 2019 + SQL Server Management Studio (SSMS) 19

********************************************************************************

在 Exchange 上相同的帳號、密碼,

用 System.Net.Mail.MailMessage 透過 Exchange 寄信正常 

用 MailKit 透過 Exchange 寄信出現 "5.7.60 SMTP; Client does not have permissions to send as this sender"

怎麼回事 ?

ChatGPT

這個狀況非常常見,原因主要是 Exchange 的身分驗證與寄件人權限機制 導致的

MailKit 嘗試以一個「未被授權的寄件者」身份發信,Exchange 判定該帳號沒有 “Send As” 權限。

🧠 背後原理差異

1️⃣ System.Net.Mail 與 Exchange 的行為

System.Net.Mail 通常使用傳統 SMTP AUTH(登入帳號作為寄件者),Exchange 會「自動容忍」寄件人欄(From:)與登入帳號相同的情況。有些舊 Exchange 甚至會自動改寫寄件人成為登入者帳號。

例如:


            
var msg = new MailMessage("userA@example.com", "test@example.com", "Test", "Hello");
var smtp = new SmtpClient("exchange.example.com");
smtp.Credentials = new NetworkCredential("userA@example.com", "password");
smtp.Send(msg);

✅ 正常寄出。

2️⃣ MailKit 的行為

MailKit 比較嚴格,它會「照原樣」送出 MAIL FROM: 與 From: 標頭。

如果你的程式這樣寫:

var message = new MimeMessage();
message.From.Add(new MailboxAddress("userB@example.com"));
message.To.Add(new MailboxAddress("test@example.com"));
message.Subject = "Test";
message.Body = new TextPart("plain") { Text = "Hello" };

using (var client = new SmtpClient())
{
    client.Connect("exchange.example.com", 587, SecureSocketOptions.StartTls);
    client.Authenticate("userA@example.com", "password");
    client.Send(message);
    client.Disconnect(true);
}

Exchange 看到:

  • 登入帳號:userA@example.com

  • 寄件人:userB@example.com

它就會拒絕,回:

5.7.60 SMTP; Client does not have permissions to send as this sender


✅ 解法

✅ 方法一:確保寄件人與登入帳號一致

最簡單:


            
message.From.Add(new MailboxAddress("userA@example.com"));   

或乾脆讓 From 直接由登入帳號動態填入。

✅ 方法二:給帳號「Send As」或「Send on Behalf」權限

如果真的需要用別的寄件人(例如共用信箱),請在 Exchange 管理介面設定:

在 Exchange Admin Center (EAC):

  1. 選該信箱(例如 shared@example.com)
  2. 點「Mailbox Delegation」
  3. 在 Send As 欄位中加入該使用者帳號(userA@example.com)→ 或者在 Send on behalf 欄位中加入

完成後,MailKit 才能以該信箱名義發信。

✅ 方法三:確認使用的驗證方式

有時 System.Net.Mail 與 MailKit 使用不同協議層:

類別 驗證方式 備註
System.Net.Mail 基於 NTLM / Integrated Auth 內部網域帳號可通過
MailKit 預設使用 AUTH LOGIN / PLAIN 需明確授權

若你是內網 Exchange,可嘗試:


            
client.Authenticate(new SaslMechanismNtlm("DOMAIN\\userA", "password"));   


            
client.Authenticate(new SaslMechanismGssapi());   

(取決於伺服器允許的機制)

🧩 小結

原因 解法
寄件人 (From:) 與登入帳號不一致 改為相同
需要代寄別的信箱 在 Exchange 給「Send As」或「Send on behalf」權限
驗證機制不同 改用 NTLM / GSSAPI
System.Net.Mail 自動容忍,MailKit 不會 屬於設計差異,非 MailKit 錯誤

********************************************************************************

敝人最後用 "確保寄件人與登入帳號一致" 的方法,解決問題了。

(完)

相關

[研究]ASP.NET WebForm 寄信元件與 SMTP Server 寄信相容性比較

[研究]ASP.NET WebForm 寄信元件與 SMTP Server 寄信相容性比較

2025-10-17 

ASP.NET Webform 網站,用下面元件

Cpi.Net.SecureMail

System.Web.Mail.MailMessage (過時)

System.Net.Mail.MailMessage

MailKit

與下面 Mail Server 搭配,

Exchange Server

Postfix 

用 C# 寫程式寄信的相容性如何?

ChatGPT

🧩 一、相容性總覽表

寄信元件 協定支援 Exchange Server 相容性 Postfix 相容性 備註
Cpi.Net.SecureMail SMTP / SMTPS (465, 587) ✅ 良好(支援 AUTH LOGIN / NTLM) ✅ 良好 商業套件,封裝較完善,常用於舊專案。
System.Web.Mail.MailMessage (過時) CDOSYS / SMTP ⚠️ 有時會被 Exchange 拒絕 (安全性不足) ⚠️ 可用但建議不用 .NET 1.x 遺留元件,不支援 SSL/TLS,已被取代。
System.Net.Mail.MailMessage SMTP / SMTPS (465, 587) ✅ 完整支援 (Exchange SMTP AUTH) ✅ 完整支援 標準選項,支援 SSL/TLS、憑證驗證。
MailKit (MimeKit) SMTP / ESMTP / OAuth2 ✅ 支援,但需設定 “SendAs” 權限 ✅ 完整支援 最強大功能完整,支援 OAuth、STARTTLS、MIME。

🧠 二、詳細說明與差異分析

1️⃣ Cpi.Net.SecureMail

  • 📦 定位:第三方封裝 SMTP 的元件,支援 SSL。
  • 🧩 特色:
    • 支援 SMTP AUTH、TLS/SSL。
    • 可與 Exchange 或 Postfix 正常運作。
  • ⚠️ 注意事項:
    • 部分版本預設只支援「AUTH LOGIN」,若 Exchange 只啟用 NTLM/Negotiate,需手動設定。
    • 若 Exchange 要求「Send As」權限,仍須在 AD 中設定。

2️⃣ System.Web.Mail.MailMessage (過時)

  • 📦 定位:ASP.NET 1.x 時代的 CDOSYS 包裝。
  • ❌ 問題:
    • 只支援「明文 SMTP」。
    • 不支援 TLS/SSL。
    • .NET Framework 2.0 起官方建議改用 System.Net.Mail。
  • ⚠️ 現實影響:
    • 現代 Exchange Server、Postfix 預設強制加密(STARTTLS),此元件通常無法連線。
    • 若伺服器允許 25 port 明文傳送,仍可工作,但非常不安全。

3️⃣ System.Net.Mail.MailMessage

  • 📦 定位:.NET 2.0+ 內建的標準 SMTP 用 API。
  • ✅ 優點:
    • 支援 SSL (EnableSsl = true)。
    • 可設定憑證驗證、自訂 port。
    • 與 Exchange、Postfix 完全相容。
  • ⚠️ 注意事項:
    • 若用 Exchange 且出現錯誤「5.7.60 Client does not have permissions to send as this sender」,代表帳號沒有 “Send As” 權限。可由 Exchange 管理員設定。
    • 不支援 OAuth2(僅支援基本帳密驗證)。

4️⃣ MailKit / MimeKit

  • 📦 定位:現代化的 SMTP/IMAP/POP3 封裝庫。
  • ✅ 優點:
    • 完整支援 SSL/TLS、OAuth2。
    • 完全相容 Postfix。
    • 支援 Exchange(EWS 例外),但 SMTP AUTH 須正確配置。
  • ⚠️ 注意事項:
    • 若 Exchange 啟用「Modern Auth」(OAuth),需配合 Microsoft Entra 應用註冊。
    • 若只允許 NTLM 而未啟用 AUTH LOGIN/PLAIN,MailKit 會出現:
    • 5.7.60 SMTP; Client does not have permissions to send as this sender
    • 解法是在 Exchange 中允許 AUTH LOGIN 或調整「Send As」權限。

⚙️ 三、建議使用組合

環境 建議元件 備註
ASP.NET WebForm + Exchange Server(on-prem) System.Net.Mail.MailMessage 最穩定,簡單配置。若有 OAuth 要求,可升級 MailKit。
ASP.NET WebForm + Exchange Online (Microsoft 365) MailKit 支援 OAuth2 / Modern Auth。
ASP.NET WebForm + Postfix System.Net.Mail.MailMessageMailKit 兩者皆穩定。MailKit 若需大量寄信效能更好。
舊專案維護,不可改架構 Cpi.Net.SecureMail 可作為過渡方案,但建議逐步改為 System.Net.Mail。

🧾 四、簡短結論

用途 建議
安全性優先 MailKit(支援 TLS + OAuth)
相容性最佳 System.Net.Mail.MailMessage
老舊程式維護 Cpi.Net.SecureMail
不再建議使用 System.Web.Mail.MailMessage(過時)

(完)

2025年10月16日 星期四

[研究]ASP.NET, WebForm, 請問 Cpi.Net.SecureMail 和 MailKit 優缺點差異 ?

[研究]ASP.NET, WebForm, 請問 Cpi.Net.SecureMail 和 MailKit 優缺點差異 ?

2025-10-15

ASP.NET, WebForm, 請問 Cpi.Net.SecureMail 和 MailKit 優缺點差異 ?

ChatGPT (以下敝人沒去驗證)

🔹 一、基本定位與背景

項目 Cpi.Net.SecureMail MailKit
來源 商業元件(CodePorting、Chilkat SecureMail 或類似 CPI 套件) 開源(MimeKit/MailKit,由 Jeffrey Stedfast 維護)
授權 通常需授權費或企業購買 MIT License,免費開源
維護狀況 多數版本已停止更新多年 積極維護、支援 .NET Framework / .NET 6+
相依套件 通常內含完整功能包 依賴 MimeKit(同作者)

🔹 二、支援功能比較

功能項目 Cpi.Net.SecureMail MailKit
SMTP / POP3 / IMAP ✅ 支援 ✅ 支援完整協定
SSL / TLS / STARTTLS ✅(部分老版本僅支援 SSLv3/TLS 1.0) ✅ 支援現代 TLS 1.2 / 1.3
OAuth2 驗證 🚫 通常不支援 ✅ 完整支援(含 Gmail、Outlook OAuth2)
MIME、附件、多語編碼 ✅ 支援但有限 ✅ 功能極強(內含 MimeKit)
S/MIME 簽章與加密 ✅ 內建(主要賣點) ✅ 支援(透過 MimeKit.Secure)
HTML 郵件支援
郵件草稿/收件處理 🚫(寄信為主) ✅ 支援收發雙向作業
.NET Core / .NET 6+ 🚫 通常僅支援 .NET Framework 2.0–4.8 ✅ 完全支援
SMTP 驗證模式 典型:LOGIN、PLAIN 多樣:LOGIN、PLAIN、NTLM、XOAUTH2、CRAM-MD5 等

🔹 三、開發與整合難易度

項目 Cpi.Net.SecureMail MailKit
API 風格 接近 System.Net.Mail,簡單易懂 較底層但彈性高
文件資源 通常較少、需靠舊文件或範例 文件齊全(官方 + GitHub + 社群)
例外處理 多為 SecureMailException 類別 使用標準 ServiceNotAuthenticatedException

🔹 四、性能與安全性

項目 Cpi.Net.SecureMail MailKit
傳輸效能 一般(同步為主) 高(支援非同步 async/await)
安全性 若版本舊,TLS 不安全 現代 TLS 1.3 / 完整憑證驗證
兼容性 舊 Exchange / 舊 SMTP Server 相容佳 新雲端郵件 (Gmail, Office 365) 相容佳

🔹 五、使用範例比較
✅ Cpi.Net.SecureMail (假設版本支援 SSL)

SecureMail mail = new SecureMail();
mail.From = "from@example.com";
mail.To = "to@example.com";
mail.Subject = "Test";
mail.Body = "Hello World!";
mail.SmtpServer = "smtp.example.com";   
mail.User = "account";
mail.Password = "password";
mail.Ssl = true;
mail.Send();

MailKit

using MailKit.Net.Smtp;
using MimeKit;

var message = new MimeMessage();
message.From.Add(new MailboxAddress("Sender", "from@example.com"));
message.To.Add(new MailboxAddress("Receiver", "to@example.com"));
message.Subject = "Test";
message.Body = new TextPart("plain") { Text = "Hello World!" };

using (var client = new SmtpClient())
{
    client.Connect("smtp.example.com", 587, MailKit.Security.SecureSocketOptions.StartTls);   
    client.Authenticate("account", "password");
    client.Send(message);
    client.Disconnect(true);
}

🔹 六、總結建議

使用場景 推薦方案 理由
舊 ASP.NET WebForms 專案(.NET 2.0–3.5) Cpi.Net.SecureMail 若已整合且不需改框架
新 ASP.NET 4.6+ 或 .NET 6+ MailKit 安全性高、支援 OAuth2、文件完整
需加簽/加密 (S/MIME) MailKit(透過 MimeKit.Secure) 較新、可整合現代 CA 憑證
要相容 Gmail、Outlook、Office365 MailKit 舊 SecureMail 不支援現代驗證

🔹 七、簡短結論

評價面 建議
相容性與安全性 MailKit 勝
功能完整度 MailKit 勝
開發簡單度(舊專案) Cpi.Net.SecureMail 勝
未來維護性 MailKit 勝

(完)

2023年2月22日 星期三

[研究][ASP.NET]MaiKit和MimeKit套件,相同Email,某網段收到附檔 .ZIP 正常,某網段附檔變成 .dat

[研究][ASP.NET]MaiKit和MimeKit套件,相同Email,某網段收到附檔 .ZIP 正常,某網段附檔變成 .dat

2023-02-22

環境:Visual Studio 2022 + ASP.NET + WebForm + Web Application + C#

********************************************************************************

這表示電子郵件在經過某些網路路徑、郵件伺服器、資安設備、資安軟體時,發生了編碼或格式轉換的問題。具體而言,電子郵件通常以純文本或多部分格式(Multipart)的方式發送,Multipart格式允許在電子郵件中包含多個部分,例如文本、圖像或其他檔案,並且每個部分都有自己的MIME類型和編碼方式。

在某些情況下,經過轉發、轉送或轉碼等過程後,郵件中的檔案部分的MIME類型可能被更改為不正確的類型,例如將PDF檔案的MIME類型更改為應用程序/octet-stream(即 .dat 文件),這導致收件人在下載附檔時會看到 .dat 的副檔名。

如果郵件中包含的附檔格式不常見或特殊,有些郵件伺服器或客戶端可能無法正確識別這些檔案的MIME類型,從而將其解釋為應用程序/octet-stream(即 .dat 文件)。

如果無法從網路路徑、郵件伺服器、資安設備、資安軟體解決 (不會處理、或不支援),或可嘗試修改程式碼,避開問題。

********************************************************************************

具體範例,把 "octet-stream" 改成 "x-unknown",實際測試可以解決;但不保證每個場合都可以這樣解決,有可能您的環境有其他問題。

/ 有問題
//MimePart attachment = new MimePart("application", "octet-stream")

MimePart attachment = new MimePart("application", "x-unknown")

//Expected '/' at position 11
//描述: 在執行目前 Web 要求的過程中發生未處理的例外狀況。請檢閱堆疊追蹤以取得錯誤的詳細資訊,以及在程式碼中產生的位置。
//MimePart attachment = new MimePart("application")


(完)

2023年2月20日 星期一

[研究][C#][ASP.NET] 自動加簽或不加簽寄信(使用 MailKit 和 MimeKit)(七)多收件者與單一附件(三)的改良

[研究][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

[研究][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
更新補充一些資訊,更新到 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

2023年1月18日 星期三

[研究]MailKit, MimeKit, MailKitLite, MimeKitLite 差異比較

[研究]MailKit, MimeKit, MailKitLite, MimeKitLite 差異比較

2023-01-18

MailKit 和 MimeKit 是兩個.NET平台上用於處理電子郵件的開源庫。

MailKit是一個功能強大的郵件客戶端庫,它提供了一個高級API,可以方便地與各種電子郵件協議(如SMTP、POP3、IMAP)進行交互。 MailKit還提供了對S/MIME和PGP加密的支持,可以用於對電子郵件進行加密和解密。

MimeKit則是一個專注於郵件消息解析和生成的庫,它可以方便地解析和生成各種郵件消息格式,如MIME和S/MIME消息。 MimeKit也支持對PGP加密的解析和生成。

MailKitLite和MimeKitLite是MailKit和MimeKit的輕量級版本,它們針對某些特定場景進行了優化和簡化,以減少庫的大小和複雜度。

總體而言,MailKit和MimeKit提供了一個完整而強大的郵件處理解決方案,可以滿足各種不同的需求,包括處理電子郵件協議、加密和解密電子郵件、解析和生成郵件消息等等。而MailKitLite和MimeKitLite則提供了一個較為輕量級的解決方案,適用於那些對庫的大小和複雜度有限制的場景。

4者官方網站都是
http://www.mimekit.net/

MailKit 3.4.3 和 MailKitLite 3.4.3
支援.NET 6.0 .NET Standard 2.0 .NET Framework 4.6.2
MailKit is an Open Source cross-platform .NET mail-client library that is based on MimeKit and optimized for mobile devices.
https://www.nuget.org/packages/MailKit
https://www.nuget.org/packages/MailKitLite/

MimeKit 3.4.3 和 MimeKitLite 3.4.3
支援.NET 6.0 .NET Standard 2.0 .NET Framework 4.6.2
MimeKit is an Open Source library for creating and parsing MIME, S/MIME and PGP messages on desktop and mobile platforms.
https://www.nuget.org/packages/MimeKit
https://www.nuget.org/packages/MimeKitLite

差異

https://github.com/jstedfast/MimeKit
MimeKit.sln Removed Mono.Data.Sqlite
MimeKitLite.sln Dropped the Net45-specific projects/solutions

https://github.com/jstedfast/MimeKit/blob/master/README.md
MimeKit.sln - includes projects for .NET 4.5/4.6/4.7/4.8, .NETStandard 1.3/1.6/2.0 as well as the unit tests.
MimeKitLite.sln - includes projects for the stripped-down versions of MimeKit that drop support for crypto.
MimeKit.sln - 包括 .NET 4.5/4.6/4.7/4.8、.NETStandard 1.3/1.6/2.0 的項目以及單元測試。
MimeKitLite.sln - 包括 MimeKit 的精簡版本的項目,它放棄了對加密的支持。

********************************************************************************

Visual Studio 2022 NuGet 安裝 MailKit 3.4.3 要求

Portable.BouncyCastle.1.9.0

System.Buffers.4.5.1

System.Numerics.Vectors.4.5.0

System.Runtime.CompilerServices.Unsafe.6.0.0

System.Memory.4.5.5

MimeKit.3.4.3

********************************************************************************

Visual Studio 2022 NuGet 安裝 MailKitLite 3.4.3 要求

System.Buffers.4.5.1

System.Numerics.Vectors.4.5.0

System.Runtime.CompilerServices.Unsafe.6.0.0

System.Memory.4.5.5

MimeKitLite.3.4.3

********************************************************************************

使用 MailKitLite 3.43 和 MimeKitLite 3.43 情況

using MailKit.Net.Smtp;	// 錯誤:找不到類型或命名空間名稱 'MailKit'
using MailKit.Scurity;	// 錯誤:找不到類型或命名空間名稱 'MailKit'

using MailKitLite.Net.Smtp;	// 錯誤:找不到類型或命名空間名稱 'MailKitLite'	
using MailKit.Security;		// 錯誤:找不到類型或命名空間名稱 'MailKitLite'

using MimeKit;
using MimeKit.Cryptography;
using MimeKit.Utils;

using MimeKitLite;		// 錯誤:找不到類型或命名空間名稱 'MimeKitLite'
using MimeKitLite.Cryptography;	// 錯誤:找不到類型或命名空間名稱 'MimeKitLite'
using MimeKitLite.Utils;	// 錯誤:找不到類型或命名空間名稱 'MimeKitLite'

編譯會出錯

CS0234 命名空間 'MimeKit.Cryptography' 中沒有類型或命名空間名稱 'TemporarySecureMimeContext' 

CS0103 名稱 'MultipartSigned' 不存在於目前的內容

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);
                }


下面會出現錯誤

命名空間 'MimeKit.Cryptography' 中沒有類型或命名空間名稱 'SecureMailboxAddress'

MimeKit.Cryptography.SecureMailboxAddress mailbox = new MimeKit.Cryptography.SecureMailboxAddress(
                    System.Text.Encoding.GetEncoding("UTF-8"),
                    "信箱",
                    new List<string>(),
                    "帳號@abcdef.com.tw",
                    ""
                );

下面會出現錯誤

using (var client = new MailKitLite.Net.Smtp.SmtpClient
            {
                ServerCertificateValidationCallback = (s, c, h, ee) => true
            })

下面會出現錯誤

using (var client = new MailKit.Net.Smtp.SmtpClient
            {
                ServerCertificateValidationCallback = (s, c, h, ee) => true
            })

下面會出現錯誤

CS0117 'SmtpClient' 未包含 'ServerCertificateValidationCallback' 的定義
using (var client = new SmtpClient
            {
                ServerCertificateValidationCallback = (s, c, h, ee) => true
            })


(完)


相關

[研究][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

[研究][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
更新補充一些資訊,更新到 2021-11-29

[研究][ASP.NET]單一或多個 Email 格式驗證 (使用C#)

[研究]單一或多個 Email 格式驗證 (使用 HTML5)

[研究][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

2023年1月16日 星期一

[研究][C#][ASP.NET] 自動加簽或不加簽寄信(使用 MailKit 和 MimeKit)(六)附件改良

[研究][C#][ASP.NET] 自動加簽或不加簽寄信(使用 MailKit 和 MimeKit)(六)附件改良

2023-01-16

********************************************************************************
相關數篇

[研究][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

[研究][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
更新補充一些資訊,更新到 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.Net;
using System.Net.Mail;
using System.Security.Cryptography.X509Certificates;
using System.Web;
using System.Web.UI.WebControls;

//namespace WebApplication1.App_Start
namespace WebApplication1
{
    public class CommonMailKit
    {
        public static string SendMail(
            string emailSubject,
            string emailContent,
            string toAddressList,
            string ccAddressList,
            string bccAddressList,
            string attacFileName,
            MemoryStream attacFileNameMemoryStream)
        {

            // http://www.mimekit.net/docs/html/Creating-Messages.htm
            var message = new MimeMessage();
            //message.From.Add(new MailboxAddress("User123", "user123@abcdef.com.tw"));
            MimeKit.Cryptography.SecureMailboxAddress mailbox = new MimeKit.Cryptography.SecureMailboxAddress(
                    System.Text.Encoding.GetEncoding("UTF-8"),
                    "信箱",
                    new List<string>(),
                    "帳號@abcdef.com.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@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
            //"
            //            };

            // 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 != "")
            {
                builder.Attachments.Add(attacFileName, attacFileNameMemoryStream);
            }
            // 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 MailKit.Net.Smtp.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.abcdef.com.tw", 25, false);// 非 SSL連線
                //client.Connect("smtp.abcdef.com.tw", 25, SecureSocketOptions.Auto);// Auto SSL連線
                //client.Connect("smtp.abcdef.com.tw", 465, SecureSocketOptions.Auto);
                //client.Connect("smtp.abcdef.com.tw", 587, SecureSocketOptions.Auto);

                // 某些 Mail Server (SMTP) 寄信會要求帳號、密碼
                // 某些 Mail Server (SMTP) 的帳號是完整含 @ 的Email,有些是 @ 之前的
                //client.Authenticate("帳號", "密碼");
                //client.Authenticate("zzzz@gmail.com", "密碼");

                // Pmail Server 驗證必須 bypass,必須有下面 Code
                // 否則會出現錯誤:根據驗證程序,遠端憑證是無效的。
                // 目前把 ServerCertificateValidationCallback 加在上方
                //MailKit.Net.Smtp.SmtpClient client = new MailKit.Net.Smtp.SmtpClient
                //{
                //    ServerCertificateValidationCallback = (s, c, h, ee) => true
                //};


                //string localIP = Common.GetLocalIPv4();
                string localIP = 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 申請的是 帳號@abcdef.com.tw
                    // Exchange Server Email : re帳號@abcdef.com.tw 一般帳號,寄信使用
                    // Exchange Server Email : 帳號@abcdef.com.tw 群組帳號,無法寄信
                    // 真實寄信用 re帳號@abcdef.com.tw,但名義上的寄信者是 帳號@abcdef.com.tw
                    // 為了和 Email Cert 的 帳號@abcdef.com.tw 相符合
                    //client.Connect("smtp.icst.org.tw", 25, false); // icst.org.tw 對外應該已宣稱無使用了

                    // IIS SMTP 要設定 None,Auto 會失敗
                    //client.Connect("smtp.abcdef.com.tw", 25, SecureSocketOptions.Auto);
                    //client.Connect("smtp.abcdef.com.tw", 25, SecureSocketOptions.None);

                    //client.Connect("smtp.abcdef.com.tw", 25, false);
                    //client.Authenticate("re帳號", "密碼");

                    client.Connect("10.3.99.25", 25, false);
                    client.Authenticate("se", "123456");

                }
                if (localIP.Substring(0, 7) == "192.168.")
                {
                    // 「對外服務網段」只能用 Pmail ( 192.168.3.25) 寄信
                    // Pmail 帳號 和 OA LAN 帳號不同
                    // Pmail Server Email : 帳號@abcdef.com.tw 一般帳號
                    // Email Cert 申請的是 帳號@abcdef.com.tw

                    // IIS SMTP 要設定 None,Auto 會失敗
                    //client.Connect("192.168.3.25", 25, SecureSocketOptions.Auto);
                    //client.Connect("smtp.abcdef.com.tw", 25, SecureSocketOptions.None);
                    client.Connect("192.168.3.25", 25, false);
                    client.Authenticate("帳號", "密碼");
                }

                try
                {
                    //foreach (var message in messages)
                    //{
                    // Fortify SCA : Insecure SSL: Server Identity Verification Disabled
                    client.Send(message);
                    //}

                    client.Disconnect(true);
                    return "";  //成功
                }
                catch (Exception ex)
                {
                    if (ex != null)
                    {
                        return ex.Message.ToString();
                    }
                    else
                    {
                        return "不明錯誤。";
                    }
                }
            }
        }

        #region == public static string GetLocalIPv4() ==
        public static string GetLocalIPv4()
        {
            string localIPv4 = "";
            // 取得本機名稱
            string strHostName = Dns.GetHostName();
            // 取得本機的IpHostEntry類別實體,用這個會提示已過時
            //IPHostEntry iphostentry = Dns.GetHostByName(strHostName);

            // 取得本機的IpHostEntry類別實體,MSDN建議新的用法
            IPHostEntry iphostentry = Dns.GetHostEntry(strHostName);

            // 取得所有 IP 位址
            foreach (IPAddress ipaddress in iphostentry.AddressList)
            {
                // 只取得IP V4的Address
                if (ipaddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                {
                    if (ipaddress.ToString().Substring(0, 3) != "192")
                        localIPv4 = ipaddress.ToString();
                }
            }
            return localIPv4;
        }
        #endregion
    }
}


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:FileUpload ID="FileUpload1" runat="server" AllowMultiple="true" /><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)
        {
            Label1.Text = "";
            string sendMailResult = CommonMailKit.SendNoCertAndCertMailAttachListbyMailKit
                ("主旨-附件測試", "內容",
                "user123@abcdef.com.tw","","", FileUpload1);
            if (sendMailResult == "")
            {
                Label1.ForeColor = System.Drawing.Color.Green;
                Label1.Text = DateTime.Now.ToString()+ "成功。";
            }
            else
            {
                Label1.ForeColor = System.Drawing.Color.Red;
                Label1.Text = DateTime.Now.ToString() + sendMailResult;
            }
            //----------
            string sendMailResult2 = CommonMailKit.SendNoCertAndCertMailAttachListbyMailKit
                ("主旨-附件測試", "內容",
                ""user123@abcdef.com.tw", "", "", null);
if (sendMailResult2 == "") { Label1.ForeColor = System.Drawing.Color.Green; Label1.Text = DateTime.Now.ToString() + "成功。"; } else { Label1.ForeColor = System.Drawing.Color.Red; Label1.Text = DateTime.Now.ToString() + sendMailResult2; } } } }


(完)

相關

[研究][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

2022年6月13日 星期一

[研究][C#][ASP.NET] 自動加簽或不加簽寄信(使用 MailKit 和 MimeKit)(五)多收件者與多附件

[研究][C#][ASP.NET] 自動加簽或不加簽寄信(使用 MailKit 和 MimeKit)(五)多收件者與多附件

2022-06-13

********************************************************************************
相關數篇

[研究][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

[研究][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
更新補充一些資訊,更新到 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.Configuration;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Web;
using System.Web.UI.WebControls;

namespace WebApplication1
{
    public static class CommonMailKit
    {
        #region == SendNoCertAndCertMailAttachListbyMailKit ==
        public static string SendNoCertAndCertMailAttachListbyMailKit(
            string emailSubject,
            string emailContent,
            string toAddressList,
            string ccAddressList,
            string bccAddressList,
            FileUpload emailAttachList)
        {

            // http://www.mimekit.net/docs/html/Creating-Messages.htm
            var message = new MimeMessage();

            //message.From.Add(new MailboxAddress("User123", "user123@abcdef.com.tw"));

            MimeKit.Cryptography.SecureMailboxAddress mailbox = new MimeKit.Cryptography.SecureMailboxAddress(
                    System.Text.Encoding.GetEncoding("UTF-8"),
                    "XXXX系統",
                    new List<string>(),
                    "user123@abcdef.com.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("User567", "user567@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 //" // }; // 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); builder.TextBody = "EmailBody"; // 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; } } // 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(); 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); // 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()) { // IIS SMTP 要設定 None,Auto 會失敗 //client.Connect("localhost", 25, SecureSocketOptions.None); //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", 465, SecureSocketOptions.Auto); //client.Connect("smtp.abcdef.com.tw", 587, SecureSocketOptions.Auto); // 某些 Mail Server (SMTP) 寄信惠要求帳號、密碼 // 某些 Mail Server (SMTP) 的帳號是完整含 @ 的Email,有些是 @ 之前的 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 "不明錯誤。"; } } } } #endregion } }


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:FileUpload ID="FileUpload1" runat="server" AllowMultiple="true" /><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)
        {
            Label1.Text = "";
            string sendMailResult = CommonMailKit.SendNoCertAndCertMailAttachListbyMailKit
                ("主旨-附件測試", "內容",
                "user123@abcdef.com.tw","","", FileUpload1);
            if (sendMailResult == "")
            {
                Label1.ForeColor = System.Drawing.Color.Green;
                Label1.Text = DateTime.Now.ToString()+ "成功。";
            }
            else
            {
                Label1.ForeColor = System.Drawing.Color.Red;
                Label1.Text = DateTime.Now.ToString() + sendMailResult;
            }
            //----------
            string sendMailResult2 = CommonMailKit.SendNoCertAndCertMailAttachListbyMailKit
                ("主旨-附件測試", "內容",
                ""user123@abcdef.com.tw", "", "", null);
if (sendMailResult2 == "") { Label1.ForeColor = System.Drawing.Color.Green; Label1.Text = DateTime.Now.ToString() + "成功。"; } else { Label1.ForeColor = System.Drawing.Color.Red; Label1.Text = DateTime.Now.ToString() + sendMailResult2; } } } }

實際測試OK。

********************************************************************************

2022-06-20 補

單獨測試本篇此 class 是正常的,如果方案/專案中有其他寄信套件,下面這行可能會 throw 出現問題 The SmtpClient is already connected.

var message = new MimeKit.MimeMessage();  


(完)

相關

[研究][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