354 lines
12 KiB
C#
354 lines
12 KiB
C#
|
||
//--------------------------------------------------------------------
|
||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
||
// 生成时间 2025-10-28 06:22:42Z
|
||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||
//--------------------------------------------------------------------
|
||
using IRaCIS.Core.Application.Interfaces;
|
||
using IRaCIS.Core.Application.ViewModel;
|
||
using IRaCIS.Core.Domain.Models;
|
||
using IRaCIS.Core.Infra.EFCore;
|
||
using IRaCIS.Core.Infrastructure.Extention;
|
||
using MailKit;
|
||
using MailKit.Net.Imap;
|
||
using MailKit.Search;
|
||
using MailKit.Security;
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using Microsoft.Extensions.Options;
|
||
using MimeKit;
|
||
using System.Net.Mail;
|
||
using System.Threading.Tasks;
|
||
namespace IRaCIS.Core.Application.Service;
|
||
|
||
/// <summary>
|
||
/// 邮件日志
|
||
/// </summary>
|
||
/// <param name="_emailLogRepository"></param>
|
||
/// <param name="systemEmailConfig"></param>
|
||
/// <param name="_mapper"></param>
|
||
/// <param name="_userInfo"></param>
|
||
/// <param name="_localizer"></param>
|
||
[ApiExplorerSettings(GroupName = "Common")]
|
||
public class EmailLogService(IRepository<EmailLog> _emailLogRepository,
|
||
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig,
|
||
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer): BaseService, IEmailLogService
|
||
{
|
||
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
||
|
||
[HttpPost]
|
||
public async Task<PageOutput<EmailLogView>> GetEmailLogList(EmailLogQuery inQuery)
|
||
{
|
||
|
||
PageOutput<EmailLogView> pageOutput = new PageOutput<EmailLogView>();
|
||
|
||
switch (inQuery.EmailStateEnum)
|
||
{
|
||
case EmailState.Success:
|
||
|
||
using (var client = new ImapClient())
|
||
{
|
||
try
|
||
{
|
||
client.Connect(_systemEmailConfig.Imap, 993, SecureSocketOptions.SslOnConnect);
|
||
client.Authenticate(_systemEmailConfig.FromEmail, _systemEmailConfig.AuthorizationCode);
|
||
var sentFolder = client.GetFolder("已发送");
|
||
sentFolder.Open(FolderAccess.ReadOnly);
|
||
|
||
// 构建搜索查询条件
|
||
var searchQuery = BuildSearchQuery(inQuery);
|
||
|
||
var orderBy = new[] { OrderBy.ReverseDate };
|
||
// 搜索符合条件的邮件UID
|
||
|
||
|
||
if (client.Capabilities.HasFlag(ImapCapabilities.Sort))
|
||
{
|
||
Console.WriteLine("服务器支持 SORT 扩展");
|
||
}
|
||
else
|
||
{
|
||
Console.WriteLine("服务器不支持 SORT,需本地排序");
|
||
}
|
||
|
||
|
||
//var uids = sentFolder.Sort(searchQuery, orderBy).Skip((inQuery.PageIndex - 1) * inQuery.PageSize).Take(inQuery.PageSize).ToList();
|
||
|
||
var uids = sentFolder.Search(searchQuery).Skip((inQuery.PageIndex - 1) * inQuery.PageSize).Take(inQuery.PageSize).ToList();
|
||
|
||
// 获取邮件并排序(按时间倒序)
|
||
var emailList = GetEmailsWithSorting(sentFolder, uids);
|
||
|
||
// 应用内存中的过滤条件(对于无法通过IMAP搜索的条件)
|
||
//var filteredEmails = ApplyMemoryFilters(emailList, inQuery);
|
||
|
||
pageOutput.TotalCount = sentFolder.Search(searchQuery).Count();
|
||
pageOutput.PageIndex = inQuery.PageIndex;
|
||
pageOutput.PageSize = inQuery.PageSize;
|
||
|
||
|
||
|
||
pageOutput.CurrentPageData = emailList;
|
||
|
||
sentFolder.Close();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
}
|
||
finally
|
||
{
|
||
client.Disconnect(true);
|
||
}
|
||
}
|
||
|
||
return pageOutput;
|
||
case EmailState.Error:
|
||
var emailLogQueryable = _emailLogRepository
|
||
|
||
.ProjectTo<EmailLogView>(_mapper.ConfigurationProvider);
|
||
|
||
var pageList = await emailLogQueryable.ToPagedListAsync(inQuery);
|
||
|
||
return pageList;
|
||
|
||
}
|
||
|
||
return pageOutput;
|
||
|
||
|
||
|
||
|
||
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 邮件筛选条件构建
|
||
/// </summary>
|
||
/// <param name="query"></param>
|
||
/// <returns></returns>
|
||
private SearchQuery BuildSearchQuery(EmailLogQuery query)
|
||
{
|
||
var searchQuery = SearchQuery.All;
|
||
|
||
// 日期范围筛选
|
||
if (query.EmailStartDate.HasValue || query.EmailEndDate.HasValue)
|
||
{
|
||
var startDate = query.EmailStartDate ?? DateTime.MinValue;
|
||
var endDate = query.EmailEndDate ?? DateTime.MaxValue;
|
||
|
||
searchQuery = searchQuery.And(SearchQuery.DeliveredAfter(startDate)
|
||
.And(SearchQuery.DeliveredBefore(endDate.AddDays(1)))); // 包含结束日期当天
|
||
}
|
||
|
||
// 主题关键词筛选(如果IMAP服务器支持)
|
||
//if (!string.IsNullOrEmpty(query.ToRecipientName))
|
||
//{
|
||
// searchQuery = searchQuery.And(SearchQuery.HeaderContains("To", query.ToRecipientName));
|
||
//}
|
||
|
||
if (!string.IsNullOrEmpty(query.ToRecipientName))
|
||
{
|
||
searchQuery = searchQuery.And(SearchQuery.SubjectContains(query.ToRecipientName));
|
||
|
||
}
|
||
|
||
if (!string.IsNullOrEmpty(query.ToRecipientName))
|
||
{
|
||
searchQuery = searchQuery.And(SearchQuery.HeaderContains("Cc", query.CcRecipientName));
|
||
}
|
||
|
||
return searchQuery;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 邮件排序处理
|
||
/// </summary>
|
||
/// <param name="sentFolder"></param>
|
||
/// <param name="uids"></param>
|
||
/// <returns></returns>
|
||
private List<EmailLogView> GetEmailsWithSorting(IMailFolder sentFolder, IList<UniqueId> uids)
|
||
{
|
||
var emailList = new List<EmailLogView>();
|
||
|
||
|
||
|
||
// 获取完整的邮件信息
|
||
foreach (var uid in uids)
|
||
{
|
||
try
|
||
{
|
||
var message = sentFolder.GetMessage(uid);
|
||
var emailView = ConvertToEmailLogView(uid, message);
|
||
emailList.Add(emailView);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"处理邮件 {uid} 失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
return emailList;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取完整的邮件信息
|
||
/// </summary>
|
||
/// <param name="uid"></param>
|
||
/// <param name="message"></param>
|
||
/// <returns></returns>
|
||
private EmailLogView ConvertToEmailLogView(UniqueId uid, MimeMessage message)
|
||
{
|
||
var emailView = new EmailLogView
|
||
{
|
||
UniqueId = uid.ToString(),
|
||
MessageId = message.MessageId ?? string.Empty,
|
||
EmailSubject = message.Subject ?? string.Empty,
|
||
EmailDate = message.Date.UtcDateTime,
|
||
Content = message.HtmlBody ?? string.Empty,
|
||
};
|
||
|
||
// 处理发件人信息
|
||
var fromMailbox = message.From.Mailboxes.FirstOrDefault();
|
||
if (fromMailbox != null)
|
||
{
|
||
emailView.SenderAddress = fromMailbox.Address;
|
||
emailView.SenderName = fromMailbox.Name ?? string.Empty;
|
||
}
|
||
|
||
// 处理收件人
|
||
emailView.ToRecipients = message.To.Mailboxes.Select(address => new EmaliSendInfo
|
||
{
|
||
Name = address.Name ?? string.Empty,
|
||
Address = address.Address
|
||
}).ToList();
|
||
|
||
// 处理抄送人
|
||
emailView.CcRecipients = message.Cc.Mailboxes.Select(address => new EmaliSendInfo
|
||
{
|
||
Name = address.Name ?? string.Empty,
|
||
Address = address.Address
|
||
}).ToList();
|
||
|
||
//// 处理密送人
|
||
//emailView.BccRecipients = message.Bcc.Mailboxes.Select(address => new EmaliSendInfo
|
||
//{
|
||
// Name = address.Name ?? string.Empty,
|
||
// Address = address.Address
|
||
//}).ToList();
|
||
|
||
// 处理附件
|
||
//emailView.Attachments = ProcessAttachments(message);
|
||
//emailView.HasAttachments = emailView.Attachments.Any();
|
||
//emailView.AttachmentCount = emailView.Attachments.Count;
|
||
|
||
return emailView;
|
||
}
|
||
|
||
///// <summary>
|
||
///// 处理附件信息
|
||
///// </summary>
|
||
///// <param name="message"></param>
|
||
///// <returns></returns>
|
||
//private List<EmailAttachmentInfo> ProcessAttachments(MimeMessage message)
|
||
//{
|
||
// var attachments = new List<EmailAttachmentInfo>();
|
||
|
||
// foreach (var attachment in message.Attachments)
|
||
// {
|
||
// var attachmentInfo = new EmailAttachmentInfo();
|
||
|
||
// if (attachment is MimePart mimePart)
|
||
// {
|
||
// attachmentInfo.FileName = mimePart.FileName ??
|
||
// mimePart.ContentType?.Name ??
|
||
// "未知文件";
|
||
// attachmentInfo.ContentType = mimePart.ContentType.MimeType;
|
||
// attachmentInfo.ContentId = mimePart.ContentId ?? string.Empty;
|
||
// attachmentInfo.IsInline = mimePart.ContentDisposition != null &&
|
||
// mimePart.ContentDisposition.Disposition.Equals("inline", StringComparison.OrdinalIgnoreCase);
|
||
|
||
// // 获取附件大小
|
||
// try
|
||
// {
|
||
// if (mimePart.ContentObject.Stream != null)
|
||
// {
|
||
// attachmentInfo.Size = mimePart.ContentObject.Stream.Length;
|
||
// }
|
||
// }
|
||
// catch
|
||
// {
|
||
// attachmentInfo.Size = 0;
|
||
// }
|
||
// }
|
||
// else if (attachment is MessagePart messagePart)
|
||
// {
|
||
// // 处理内嵌消息作为附件的情况
|
||
// attachmentInfo.FileName = "embedded-message.eml";
|
||
// attachmentInfo.ContentType = "message/rfc822";
|
||
// attachmentInfo.IsInline = false;
|
||
// }
|
||
|
||
// attachments.Add(attachmentInfo);
|
||
// }
|
||
|
||
// return attachments;
|
||
//}
|
||
|
||
/// <summary>
|
||
/// 应用内存中的过滤条件(对于无法通过IMAP搜索的条件)
|
||
/// </summary>
|
||
/// <param name="emails"></param>
|
||
/// <param name="query"></param>
|
||
/// <returns></returns>
|
||
private List<EmailLogView> ApplyMemoryFilters(List<EmailLogView> emails, EmailLogQuery query)
|
||
{
|
||
var filtered = emails.AsEnumerable();
|
||
|
||
// 收件人姓名筛选
|
||
//if (!string.IsNullOrEmpty(query.Keyword))
|
||
//{
|
||
// filtered = filtered.Where(e =>
|
||
// e.ToRecipients.Any(r =>
|
||
// r.Name.Contains(query.Keyword, StringComparison.OrdinalIgnoreCase)) ||
|
||
// e.CcRecipients.Any(r =>
|
||
// r.Name.Contains(query.Keyword, StringComparison.OrdinalIgnoreCase))
|
||
|
||
// );
|
||
//}
|
||
|
||
// 发件人姓名筛选
|
||
//if (!string.IsNullOrEmpty(query.SenderName))
|
||
//{
|
||
// filtered = filtered.Where(e =>
|
||
// e.SenderName.Contains(query.SenderName, StringComparison.OrdinalIgnoreCase));
|
||
//}
|
||
|
||
return filtered.ToList();
|
||
}
|
||
|
||
|
||
public async Task<IResponseOutput> AddOrUpdateEmailLog(EmailLogAddOrEdit addOrEditEmailLog)
|
||
{
|
||
|
||
|
||
|
||
var entity = await _emailLogRepository.InsertOrUpdateAsync(addOrEditEmailLog, true);
|
||
|
||
return ResponseOutput.Ok(entity.Id.ToString());
|
||
|
||
}
|
||
|
||
|
||
[HttpDelete("{emailLogId:guid}")]
|
||
public async Task<IResponseOutput> DeleteEmailLog(Guid emailLogId)
|
||
{
|
||
var success = await _emailLogRepository.DeleteFromQueryAsync(t => t.Id == emailLogId,true);
|
||
return ResponseOutput.Ok();
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|