using HtmlAgilityPack;
using log4net;
using MailSend.Common;
using MailSend.Common.Models;
using MailSend.Web.Models;
using MimeKit;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
namespace MailSend.Web.Controllers
{
public class MailController : Controller
{
private static ILog logger = LogManager.GetLogger("MailController");
private MailDataContext mailData = new MailDataContext();
//发送邮件
[HttpPost]
public ActionResult Send()
{
var resp = new RespCommon();
StreamReader sr = new StreamReader(Request.InputStream, Encoding.UTF8);
var strJson = sr.ReadToEnd();
if (string.IsNullOrEmpty(strJson))
{
resp.Success = false;
resp.Code = RespCommon.RespCodeParamError;
resp.Message = "参数错误";
return Json(resp);
}
logger.Debug($"收到邮件发送请求:{strJson}");
var smtpList = mailData.MailSendSmtp.AsNoTracking()
.Select(x => x.GID)
.ToList();
List listToSend = null;
try
{
listToSend = JsonConvert.DeserializeObject>(strJson);
//校验smtp参数
foreach (var item in listToSend)
{
//没有SmtpConfig参数时,需要提供发件邮箱信息
if (string.IsNullOrEmpty(item.SmtpConfig))
{
if (string.IsNullOrEmpty(item.Account)
|| string.IsNullOrEmpty(item.Password)
|| string.IsNullOrEmpty(item.Server)
|| item.Port == 0)
{
resp.Success = false;
resp.Code = RespCommon.RespCodeParamError;
resp.Message = "发件邮箱信息无效";
return Json(resp);
}
else
{
var smtpDB = mailData.MailSendSmtp.FirstOrDefault(x => x.Account == item.Account);
if (smtpDB == null)
{
smtpDB = new MailSendSmtp();
smtpDB.GID = Guid.NewGuid().ToString();
smtpDB.Account = item.Account;
mailData.MailSendSmtp.Add(smtpDB);
}
smtpDB.Password = item.Password;
smtpDB.Port = item.Port;
smtpDB.Server = item.Server;
smtpDB.UseSSL = item.UseSSL;
mailData.SaveChanges();
item.SmtpConfig = smtpDB.GID;
}
}
else
{
if (!smtpList.Contains(item.SmtpConfig))
{
resp.Success = false;
resp.Code = RespCommon.RespCodeParamError;
resp.Message = "SmtpConfig无效";
return Json(resp);
}
}
}
}
catch
{
logger.Error($"JSON格式有误,解析失败:{strJson}");
resp.Success = false;
resp.Code = RespCommon.RespCodeParamError;
resp.Message = "JSON格式有误,解析失败";
return Json(resp);
}
foreach (var item in listToSend)
{
if (string.IsNullOrEmpty(item.SendTo))
{
resp.Success = false;
resp.Code = RespCommon.RespCodeParamError;
resp.Message = "接收人不能为空";
return Json(resp);
}
if (string.IsNullOrEmpty(item.Title))
{
resp.Success = false;
resp.Code = RespCommon.RespCodeParamError;
resp.Message = "标题不能为空";
return Json(resp);
}
if (string.IsNullOrEmpty(item.Body))
{
resp.Success = false;
resp.Code = RespCommon.RespCodeParamError;
resp.Message = "正文不能为空";
return Json(resp);
}
var mailSend = new Common.MailSend();
mailSend.GID = Guid.NewGuid().ToString().Replace("-", "");
mailSend.SendTo = item.SendTo;
mailSend.CCTo = item.CCTo;
mailSend.Title = item.Title;
mailSend.Body = item.Body;
mailSend.SmtpConfig = item.SmtpConfig;
mailSend.ShowName = item.ShowName;
//附件处理
if (item.Attaches != null && item.Attaches.Count > 0)
{
var list = new List();
foreach (var att in item.Attaches)
{
if (string.IsNullOrEmpty(att.AttachName))
{
resp.Success = false;
resp.Code = RespCommon.RespCodeParamError;
resp.Message = $"附件名称不能为空";
return Json(resp);
}
if (string.IsNullOrEmpty(att.AttachContent))
{
resp.Success = false;
resp.Code = RespCommon.RespCodeParamError;
resp.Message = $"附件内容不能为空:{att.AttachName}";
return Json(resp);
}
try
{
var bsArr = Convert.FromBase64String(att.AttachContent);
var ext = Path.GetExtension(att.AttachName);
var fileTmpName = Guid.NewGuid().ToString();
var tempPath = Server.MapPath("~/Temp");
if (!Directory.Exists(tempPath))
{
Directory.CreateDirectory(tempPath);
}
var fileFullPath = Path.Combine(tempPath, fileTmpName + ext);
System.IO.File.WriteAllBytes(fileFullPath, bsArr);
var attModel = new AttachFileModel();
attModel.FileName = att.AttachName;
attModel.FilePath = fileFullPath;
list.Add(attModel);
}
catch (Exception ex)
{
logger.Error($"附件还原失败:{ex.Message}");
logger.Error(ex.StackTrace);
resp.Success = false;
resp.Code = RespCommon.RespCodeParamError;
resp.Message = $"附件还原失败:{att.AttachName}";
return Json(resp);
}
}
mailSend.AttachFiles = JsonConvert.SerializeObject(list);
}
mailData.MailSend.Add(mailSend);
}
mailData.SaveChanges();
resp.Success = true;
resp.Code = RespCommon.RespCodeSuccess;
resp.Message = "提交成功";
return Json(resp);
}
//转发邮件
[HttpPost]
public ActionResult Transmit()
{
var resp = new RespCommon();
//需上传eml文件
if (Request.Files.Count > 0)
{
var smtpList = mailData.MailSendSmtp.AsNoTracking()
.Select(x => x.GID)
.ToList();
var sendTo = Request.Form["SendTo"];
var ccTo = Request.Form["CcTo"];
var smtpConfig = Request.Form["SmtpConfig"]; //SmtpConfig
var mailAccount = Request.Form["MailAccount"];
var password = Request.Form["Password"];
int.TryParse(Request.Form["Port"], out int port);
var smtpServer = Request.Form["SmtpServer"];
bool.TryParse(Request.Form["SmtpSSL"], out bool smtpSSL);
var showName = Request.Form["ShowName"];
var prefixText = Request.Form["PrefixText"]; //前缀文本
if (string.IsNullOrEmpty(sendTo))
{
resp.Success = false;
resp.Code = RespCommon.RespCodeParamError;
resp.Message = "收件人不能为空";
return Json(resp);
}
//分拆收件邮箱地址
var sendToList = new List();
var arrTo = sendTo.Replace(",", ";").Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
foreach (var item in arrTo)
{
sendToList.Add(new MailboxAddress(item, item));
}
//分拆cc邮箱地址
var ccList = new List();
if (!string.IsNullOrEmpty(ccTo))
{
var arrCc = ccTo.Replace(",", ";").Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
foreach (var item in arrCc)
{
ccList.Add(new MailboxAddress(item, item));
}
}
MailSendSmtp smtpInfo = null;
//没有SmtpConfig参数时,需要提供发件邮箱信息
if (string.IsNullOrEmpty(smtpConfig))
{
if (string.IsNullOrEmpty(mailAccount)
|| string.IsNullOrEmpty(password)
|| string.IsNullOrEmpty(smtpServer)
|| port == 0)
{
resp.Success = false;
resp.Code = RespCommon.RespCodeParamError;
resp.Message = "发件邮箱信息无效";
return Json(resp);
}
else
{
var smtpDB = mailData.MailSendSmtp.FirstOrDefault(x => x.Account == mailAccount);
if (smtpDB == null)
{
smtpDB = new MailSendSmtp();
smtpDB.GID = Guid.NewGuid().ToString();
smtpDB.Account = mailAccount;
mailData.MailSendSmtp.Add(smtpDB);
}
smtpDB.Password = password;
smtpDB.Port = port;
smtpDB.Server = smtpServer;
smtpDB.UseSSL = smtpSSL;
mailData.SaveChanges();
smtpConfig = smtpDB.GID;
smtpInfo = smtpDB;
}
}
else
{
if (!smtpList.Contains(smtpConfig))
{
resp.Success = false;
resp.Code = RespCommon.RespCodeParamError;
resp.Message = "SmtpConfig无效";
return Json(resp);
}
smtpInfo = mailData.MailSendSmtp.AsNoTracking().First(x => x.GID == smtpConfig);
}
for (var i = 0; i < Request.Files.Count; i++)
{
var file = Request.Files[i];
if (file.ContentLength == 0)
{
resp.Success = false;
resp.Code = RespCommon.RespCodeParamError;
resp.Message = "文件内容不能为空";
return Json(resp);
}
var fileExt = Path.GetExtension(file.FileName).ToLower();
if (fileExt != ".eml")
{
resp.Success = false;
resp.Code = RespCommon.RespCodeParamError;
resp.Message = "文件格式错误";
return Json(resp);
}
MimeMessage mail = null;
try
{
mail = MimeMessage.Load(file.InputStream);
}
catch
{
resp.Success = false;
resp.Code = RespCommon.RespCodeParamError;
resp.Message = "文件格式错误";
return Json(resp);
}
if (string.IsNullOrEmpty(mail.Subject))
{
resp.Success = false;
resp.Code = RespCommon.RespCodeParamError;
resp.Message = "主题不能为空";
return Json(resp);
}
//发送人
mail.From.Clear();
mail.From.Add(new MailboxAddress(string.IsNullOrEmpty(showName) ? smtpInfo.Account : showName, smtpInfo.Account));
//收件人
mail.To.Clear();
mail.To.AddRange(sendToList);
//cc
mail.Cc.Clear();
mail.Cc.AddRange(ccList);
#region 附加前缀
var insTextList = new List();
if (!string.IsNullOrEmpty(prefixText))
{
insTextList.AddRange(prefixText.Split("\r\n".ToCharArray()));
}
if (insTextList.Count > 0)
{
var textParts = mail.BodyParts.Where(x => !x.IsAttachment && x.ContentType.MediaType == "text");
if (textParts != null && textParts.Any())
{
foreach (var part in textParts)
{
var tp = part as TextPart;
var contentText = tp.Text;
Encoding srcEncoding = null;
if (!string.IsNullOrEmpty(tp.ContentType.Charset))
{
srcEncoding = Encoding.GetEncoding(tp.ContentType.Charset);
}
if (tp.ContentType.MimeType.Contains("html"))
{
HtmlDocument htmldoc = new HtmlDocument();
var htmlEncoding = htmldoc.DetectEncodingHtml(tp.Text);
htmldoc.LoadHtml(tp.Text);
var bodyNode = htmldoc.DocumentNode.SelectSingleNode("//body");
var metaLastNode = htmldoc.DocumentNode.SelectSingleNode("//meta[last()]");
var metaCharsetNode = htmldoc.DocumentNode.SelectSingleNode("//meta[contains(@http-equiv,'Content-Type')]");
Encoding toEncoding = null;
if (srcEncoding == null)
{
srcEncoding = htmldoc.DeclaredEncoding;
}
if (srcEncoding == Encoding.ASCII || srcEncoding == Encoding.GetEncoding("iso-8859-1") || srcEncoding == null)
{
toEncoding = Encoding.UTF8;
tp.ContentType.CharsetEncoding = toEncoding;
if (metaCharsetNode != null)
{
metaCharsetNode.SetAttributeValue("content", "text/html; charset=utf-8");
}
}
else
{
toEncoding = srcEncoding;
}
if (bodyNode != null)
{
var insTextReverse = new List(insTextList.ToArray());
insTextReverse.Reverse();
foreach (var text in insTextReverse)
{
var insNode = htmldoc.CreateElement("p");
insNode.AppendChild(htmldoc.CreateTextNode(text));
bodyNode.InsertBefore(insNode, bodyNode.FirstChild);
}
MemoryStream ms = new MemoryStream();
htmldoc.Save(ms, toEncoding);
contentText = toEncoding.GetString(ms.ToArray());
}
else if (metaLastNode != null)
{
foreach (var text in insTextList)
{
var insNode = htmldoc.CreateElement("p");
insNode.AppendChild(htmldoc.CreateTextNode(text));
htmldoc.DocumentNode.InsertAfter(insNode, metaLastNode);
}
MemoryStream ms = new MemoryStream();
htmldoc.Save(ms, toEncoding);
contentText = toEncoding.GetString(ms.ToArray());
}
else
{
contentText = $"{string.Join("
", insTextList)}
{contentText}";
}
tp.SetText(toEncoding, contentText);
}
else
{
Encoding toEncoding = null;
if (srcEncoding == Encoding.ASCII || srcEncoding == Encoding.GetEncoding("iso-8859-1") || srcEncoding == null)
{
toEncoding = Encoding.UTF8;
tp.ContentType.CharsetEncoding = toEncoding;
}
else
{
toEncoding = srcEncoding;
}
contentText = $"{string.Join("\r\n", insTextList)}\r\n{contentText}";
tp.SetText(toEncoding, contentText);
tp.ContentType.CharsetEncoding = toEncoding;
}
}
}
else
{
var mult = new Multipart("mixed");
var newPart = new TextPart("plain");
newPart.SetText(Encoding.UTF8, string.Join("\r\n", insTextList));
mult.Add(newPart);
mult.Add(mail.Body);
mail.Body = mult;
}
}
#endregion
var mailSend = new Common.MailSend();
mailSend.GID = Guid.NewGuid().ToString().Replace("-", "");
mailSend.SendTo = mail.To.ToString();
mailSend.CCTo = mail.Cc?.ToString();
mailSend.Title = mail.Subject;
mailSend.SmtpConfig = smtpConfig;
mailData.MailSend.Add(mailSend);
//保存eml文件
string emlFilePath = ConfigurationManager.AppSettings["EmlFilePath"];
var saveEmlPath = string.Empty;
if (string.IsNullOrEmpty(emlFilePath))
{
saveEmlPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "EmlFiles");
}
else
{
saveEmlPath = Path.Combine(emlFilePath, "EmlFiles");
}
if (!Directory.Exists(saveEmlPath))
{
Directory.CreateDirectory(saveEmlPath);
}
var saveFileName = Path.Combine(saveEmlPath, $"{mailSend.GID}.eml");
mail.WriteTo(saveFileName);
mailSend.EmlFile = saveFileName; //记录eml文件位置
}
mailData.SaveChanges();
resp.Success = true;
resp.Code = RespCommon.RespCodeSuccess;
resp.Message = "提交成功";
return Json(resp);
}
else
{
resp.Success = false;
resp.Code = RespCommon.RespCodeParamError;
resp.Message = "请上传eml文件";
return Json(resp);
}
}
#region 发送记录查询
//发件记录
[HttpGet]
public ActionResult SendList()
{
return View();
}
[HttpGet]
public ActionResult SendListData(ReqMailSendList req, int offset = 1, int limit = 10, string sort = "", string order = "asc")
{
RespPage resp = new RespPage();
var query = from m in mailData.MailSend
join s in mailData.MailSendSmtp on m.SmtpConfig equals s.GID
select new RespMailSend
{
GID = m.GID,
SendTo = m.SendTo,
CCTo = m.CCTo,
Title = m.Title,
SendStatus = m.SendStatus,
TryCount = m.TryCount,
SendTime = m.SendTime,
CreateTime = m.CreateTime,
ShowName = m.ShowName,
Sender = s.Account,
AttachFiles = m.AttachFiles,
CustomerSend = m.CustomerSend,
ResultText = m.ResultText,
};
#region 查询条件
if (!string.IsNullOrEmpty(req.SendTo))
{
query = query.Where(x => x.SendTo.Contains(req.SendTo));
}
if (!string.IsNullOrEmpty(req.Title))
{
query = query.Where(x => x.Title.Contains(req.Title));
}
if (!string.IsNullOrEmpty(req.SendStatus))
{
query = query.Where(x => x.SendStatus == req.SendStatus);
}
if (!string.IsNullOrEmpty(req.Sender))
{
query = query.Where(x => x.Sender.Contains(req.Sender));
}
if (req.CreateTimeBegin.HasValue)
{
query = query.Where(x => x.CreateTime > req.CreateTimeBegin);
}
if (req.CreateTimeEnd.HasValue)
{
var dt = req.CreateTimeEnd.Value.AddDays(1);
query = query.Where(x => x.CreateTime < dt);
}
if (req.SendTimeBegin.HasValue)
{
query = query.Where(x => x.SendTime > req.SendTimeBegin);
}
if (req.SendTimeEnd.HasValue)
{
var dt = req.SendTimeEnd.Value.AddDays(1);
query = query.Where(x => x.SendTime < dt);
}
#endregion
resp.Success = true;
resp.Message = "查询成功";
resp.Total = query.Count();
resp.Limit = limit;
resp.Offset = offset;
resp.DataList = query.OrderByDescending(x => x.CreateTime).Skip(offset).Take(limit).ToList();
return Json(resp, JsonRequestBehavior.AllowGet);
}
[HttpGet]
public ActionResult DownloadEml(string gid)
{
var mail = mailData.MailSend.AsNoTracking().FirstOrDefault(x => x.GID == gid);
if (mail == null)
{
return Content("发送记录不存在");
}
if (System.IO.File.Exists(mail.EmlFile))
{
return File(mail.EmlFile, "application/octet-stream", $"{mail.Title}.eml");
}
else
{
return Content("EML文件丢失");
}
}
#endregion
[HttpGet]
public ActionResult Test()
{
logger.Debug($"{DateTime.Now}");
return Content("ok");
}
}
}