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