You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

655 lines
26 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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<ReqSendMail> listToSend = null;
try
{
listToSend = JsonConvert.DeserializeObject<List<ReqSendMail>>(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<AttachFileModel>();
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<MailboxAddress>();
var arrTo = sendTo.Replace(",", ";").Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
foreach (var item in arrTo)
{
sendToList.Add(new MailboxAddress(item, item));
}
//分拆cc邮箱地址
var ccList = new List<MailboxAddress>();
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<string>();
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<string>(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 = $"<p>{string.Join("</p><p>", insTextList)}</p>{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");
}
}
}