using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
using Newtonsoft.Json;
using System.IO.Compression;
namespace YLErp.MailKit
{
public static class MailSender
{
///
/// 发送邮件
///
public static void Send(SmtpConfig smtpConfig, MailSendingOption option, Action log = null)
{
if (smtpConfig == null)
{
throw new ArgumentNullException(nameof(smtpConfig));
}
if (string.IsNullOrWhiteSpace(smtpConfig.Server))
{
throw new ArgumentException("未设置SMTP Server");
}
if (string.IsNullOrWhiteSpace(smtpConfig.UserName))
{
throw new ArgumentException("未设置SMTP UserName");
}
if (option == null)
{
throw new ArgumentNullException(nameof(option));
}
if (option.MailTo == null || option.MailTo.Length < 1)
{
throw new ArgumentException("未设置收件人");
}
if (string.IsNullOrWhiteSpace(option.Subject))
{
throw new ArgumentException("未设置邮件主题");
}
var from = option.From.TrimToNull() ?? smtpConfig.From.TrimToNull() ?? smtpConfig.UserName.TrimToNull() ?? throw new ArgumentNullException("未设置发件人");
var separator = new[] { ',', ';', ',', ';' };
var message = new MimeMessage();
message.From.Add(new MailboxAddress(string.Empty, from));
foreach (var mailTo in option.MailTo)
{
message.To.Add(new MailboxAddress(string.Empty, mailTo));
}
message.Subject = option.Subject;
if (!string.IsNullOrWhiteSpace(option.CC))
{
var addrArr = option.CC.Split(separator, StringSplitOptions.RemoveEmptyEntries)
.Select(n => new MailboxAddress(string.Empty, n.Trim()));
message.Cc.AddRange(addrArr);
}
if (!string.IsNullOrWhiteSpace(option.BCC))
{
var addrArr = option.BCC.Split(separator, StringSplitOptions.RemoveEmptyEntries)
.Select(n => new MailboxAddress(string.Empty, n.Trim()));
message.Bcc.AddRange(addrArr);
}
if (option.AdditionalHeaders != null)
{
}
if (!string.IsNullOrWhiteSpace(option.HeaderEncoding))
{
message.Headers.Add(HeaderId.Encoding, option.HeaderEncoding.Trim());
}
if (!string.IsNullOrWhiteSpace(option.Priority) &&
Enum.TryParse(option.Priority.Trim(), out MessagePriority prri))
{
message.Priority = prri;
}
if (!string.IsNullOrWhiteSpace(option.ReplyTo))
{
message.ReplyTo.Add(new MailboxAddress(string.Empty, option.ReplyTo.Trim()));
}
var builder = new BodyBuilder();
if (option.IsBodyHtml)
{
builder.HtmlBody = option.Body;
}
else
{
builder.TextBody = option.Body;
}
if (option.FilesToAttach != null && option.FilesToAttach.Any(n => !string.IsNullOrWhiteSpace(n)))
{
var attaches = option.FilesToAttach.Where(n => !string.IsNullOrWhiteSpace(n)).ToArray();
for (var i = 0; i < attaches.Length; i++)
{
var attach = attaches[i];
var attachPath = attach;
if (attach.Contains("/")&& OperatingSystem.IsWindows())
{
attachPath = attach.Replace("/", "\\");
}
var attachments = builder.Attachments.Add(attachPath);
if (log != null)
{
var name = "邮件附件" + (i + 1);
log.Invoke(name, "源地址:" + attach);
log.Invoke(name, "解析地址:" + attachPath);
log.Invoke(name, "文件名称:" + attachments.ContentDisposition.FileName);
}
}
if (smtpConfig.ZipAttach)
{
using var zipStream = new MemoryStream();
using (var archive = new ZipArchive(zipStream, ZipArchiveMode.Update))
{
foreach (var attach in attaches)
{
var fileInfo = new FileInfo(attach);
var entry = archive.CreateEntry(fileInfo.Name);
using var stream = entry.Open();
var bytes = File.ReadAllBytes(fileInfo.FullName);
stream.Write(bytes, 0, bytes.Length);
}
}
builder.Attachments.Add(option.Subject + ".zip", zipStream.ToArray());
log?.Invoke("邮件附件ZIP", "Subject:" + option.Subject);
}
}
message.Body = builder.ToMessageBody();
if (!string.IsNullOrWhiteSpace(option.ContentEncoding))
{
message.Body.Headers.Add(HeaderId.Encoding, option.ContentEncoding.Trim());
}
//以outlook名义发送邮件,不会被当作垃圾邮件
message.Headers.Add("X-Priority", "3");
message.Headers.Add("X-MSMail-Priority", "Normal");
message.Headers.Add("X-Mailer", "Microsoft Outlook Express 6.00.2900.2869");
message.Headers.Add("X-MimeOLE", "Produced By Microsoft MimeOLE V6.00.2900.2869");
message.Headers.Add("ReturnReceipt", "1");
if (smtpConfig.Receipt)
{
message.Headers.Add("Disposition-Notification-To", from);
}
using var client = new SmtpClient();
// For demo-purposes, accept all SSL certificates (in case the server supports STARTTLS)
client.ServerCertificateValidationCallback = (s, c, h, e) => true;
var userName = smtpConfig.UserName;
var secureSocketOptions = SecureSocketOptions.None;
//当做exchange邮件服务器处理
if (smtpConfig.Port == 587)
{
client.SslProtocols = System.Security.Authentication.SslProtocols.Tls;
if (smtpConfig.EnableSsl)
{
secureSocketOptions = SecureSocketOptions.StartTls;
}
var index = userName.IndexOf('@');
if (index > 0)
{
userName = userName.Substring(0, index);
}
}
else if (smtpConfig.EnableSsl)
{
secureSocketOptions = SecureSocketOptions.SslOnConnect;
}
client.Connect(smtpConfig.Server, smtpConfig.Port, secureSocketOptions);
// Note: since we don't have an OAuth2 token, disable the XOAUTH2 authentication mechanism.
client.AuthenticationMechanisms.Remove("XOAUTH2");
if (!string.IsNullOrWhiteSpace(smtpConfig.Password))
{
client.Authenticate(userName, smtpConfig.Password);
}
client.Send(message);
client.Disconnect(true);
}
public static string SendApi(MailSendingOption option, Action log = null)
{
if (option == null)
{
throw new ArgumentNullException(nameof(option));
}
if (option.MailTo == null || option.MailTo.Length < 1)
{
throw new ArgumentException("未设置收件人");
}
if (string.IsNullOrWhiteSpace(option.Subject))
{
throw new ArgumentException("未设置邮件主题");
}
var baseUrl = Environment.GetEnvironmentVariable("BondOmsInterface_BaseUrl");
var emailPath = "/general/email/send";
if (string.IsNullOrEmpty(baseUrl))
{
throw new ArgumentException("未设置邮件接口地址");
}
// 创建一个HttpClient实例
using (var httpClient = new HttpClient())
{
httpClient.Timeout = TimeSpan.FromMinutes(3); // 根据需要调整
var content = new MultipartFormDataContent();
// 添加收件人
content.Add(new StringContent(string.Join(",", option.MailTo)), "to");
// 添加主题
content.Add(new StringContent(option.Subject), "subject");
// 添加邮件正文
content.Add(new StringContent(option.Body), "text");
// 添加邮件正文
content.Add(new StringContent(option.IsBodyHtml.ToString()), "isHtmlContent");
if (!string.IsNullOrWhiteSpace(option.CC))
{
content.Add(new StringContent(string.Join(",", option.CC)), "cc");
}
if (!string.IsNullOrWhiteSpace(option.BCC))
{
content.Add(new StringContent(string.Join(",", option.BCC)), "bcc");
}
// 将文件添加到请求体中
if (option.FilesToAttach != null && option.FilesToAttach.Any(n => !string.IsNullOrWhiteSpace(n)))
{
var attaches = option.FilesToAttach.Where(n => !string.IsNullOrWhiteSpace(n)).ToArray();
for (var i = 0; i < attaches.Length; i++)
{
var attach = attaches[i];
var attachPath = attach;
if (attach.Contains("/") && OperatingSystem.IsWindows())
{
attachPath = attach.Replace("/", "\\");
}
var fileInfo= new FileInfo(attachPath);
// 添加附件
var attachmentContent = new ByteArrayContent(File.ReadAllBytes(attachPath));
content.Add(attachmentContent, "files", fileInfo.Name);
if (log != null)
{
var name = "邮件附件" + (i + 1);
log.Invoke(name, "源地址:" + attach);
log.Invoke(name, "解析地址:" + attachPath);
log.Invoke(name, "文件名称:" + fileInfo.Name);
}
}
}
if (log != null) {
log.Invoke("邮件发送接口", "BaseUrl:" + baseUrl);
log.Invoke("邮件发送接口", "EmailPath:" + emailPath);
}
// 发送POST请求
var response = httpClient.PostAsync($"{baseUrl}{emailPath}", content).Result;
// 检查响应状态码
if (response.IsSuccessStatusCode)
{
// 解析响应内容并返回结果
var result = response.Content.ReadAsStringAsync().Result;
if (log != null)
{
log.Invoke("邮件发送接口", "响应内容:" + result);
}
if (string.IsNullOrEmpty(result))
{
throw new ArgumentException("发送邮件失败");
}
var trsRespone = JsonConvert.DeserializeObject(result);
if (!trsRespone.success)
{
throw new ArgumentException("发送邮件失败:"+ trsRespone.message);
}
return trsRespone.data.ToString();
}
else
{
if (log != null)
{
log.Invoke("邮件发送接口", "响应状态码:" + response.StatusCode);
log.Invoke("邮件发送接口", "响应内容:" + response.Content.ReadAsStringAsync().Result);
}
// 处理错误情况
}
}
return "";
}
///
///
///
static string TrimToNull(this string str)
{
return string.IsNullOrWhiteSpace(str) ? null : str.Trim();
}
}
}