初步完成邮件功能
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MailKit" Version="4.7.1.1" />
|
||||
<PackageReference Include="MQTTnet" Version="3.0.16" />
|
||||
<PackageReference Include="SqlSugarCore" Version="5.1.4.197" />
|
||||
<PackageReference Include="SqlSugarCore.MySql" Version="5.1.4.178" />
|
||||
|
||||
89
DMS.Infrastructure/Entities/DbEmailAccount.cs
Normal file
89
DMS.Infrastructure/Entities/DbEmailAccount.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using SqlSugar;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DMS.Infrastructure.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// 邮件账户数据库实体
|
||||
/// </summary>
|
||||
[SugarTable("email_accounts")]
|
||||
public class DbEmailAccount
|
||||
{
|
||||
/// <summary>
|
||||
/// 账户ID
|
||||
/// </summary>
|
||||
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 账户名称
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 100)]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 邮箱地址
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 255)]
|
||||
public string EmailAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// SMTP服务器地址
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 100)]
|
||||
public string SmtpServer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// SMTP端口号
|
||||
/// </summary>
|
||||
public int SmtpPort { get; set; } = 587;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用SSL
|
||||
/// </summary>
|
||||
public bool EnableSsl { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 用户名
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 100)]
|
||||
public string Username { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 100)]
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// IMAP服务器地址
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 100, IsNullable = true)]
|
||||
public string? ImapServer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// IMAP端口号
|
||||
/// </summary>
|
||||
public int ImapPort { get; set; } = 993;
|
||||
|
||||
/// <summary>
|
||||
/// 是否为默认账户
|
||||
/// </summary>
|
||||
public bool IsDefault { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用
|
||||
/// </summary>
|
||||
public bool IsActive { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreatedAt { get; set; } = DateTime.Now;
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.Now;
|
||||
}
|
||||
}
|
||||
46
DMS.Infrastructure/Entities/DbEmailLog.cs
Normal file
46
DMS.Infrastructure/Entities/DbEmailLog.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using SqlSugar;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DMS.Infrastructure.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// 邮件日志数据库实体
|
||||
/// </summary>
|
||||
[SugarTable("email_logs")]
|
||||
public class DbEmailLog
|
||||
{
|
||||
/// <summary>
|
||||
/// 日志ID
|
||||
/// </summary>
|
||||
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关联的邮件ID
|
||||
/// </summary>
|
||||
public int EmailMessageId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日志级别
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 20)]
|
||||
public string Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日志消息
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 4000)]
|
||||
public string Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 异常详情
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 2000, IsNullable = true)]
|
||||
public string? Exception { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreatedAt { get; set; } = DateTime.Now;
|
||||
}
|
||||
}
|
||||
86
DMS.Infrastructure/Entities/DbEmailMessage.cs
Normal file
86
DMS.Infrastructure/Entities/DbEmailMessage.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using SqlSugar;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DMS.Infrastructure.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// 邮件消息数据库实体
|
||||
/// </summary>
|
||||
[SugarTable("email_messages")]
|
||||
public class DbEmailMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// 邮件ID
|
||||
/// </summary>
|
||||
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关联的邮件账户ID
|
||||
/// </summary>
|
||||
public int EmailAccountId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 发件人邮箱地址
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 255)]
|
||||
public string From { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 收件人邮箱地址(多个用分号分隔)
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 1000)]
|
||||
public string To { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 抄送邮箱地址(多个用分号分隔)
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 1000, IsNullable = true)]
|
||||
public string? Cc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 密送邮箱地址(多个用分号分隔)
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 1000, IsNullable = true)]
|
||||
public string? Bcc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 邮件主题
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 500)]
|
||||
public string Subject { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 邮件正文
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 4000)]
|
||||
public string Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否为HTML格式
|
||||
/// </summary>
|
||||
public bool IsHtml { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 邮件发送状态
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 20)]
|
||||
public string Status { get; set; } = "Pending";
|
||||
|
||||
/// <summary>
|
||||
/// 发送时间
|
||||
/// </summary>
|
||||
[SugarColumn(IsNullable = true)]
|
||||
public DateTime? SentAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreatedAt { get; set; } = DateTime.Now;
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.Now;
|
||||
}
|
||||
}
|
||||
62
DMS.Infrastructure/Entities/DbEmailTemplate.cs
Normal file
62
DMS.Infrastructure/Entities/DbEmailTemplate.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using SqlSugar;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DMS.Infrastructure.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// 邮件模板数据库实体
|
||||
/// </summary>
|
||||
[SugarTable("email_templates")]
|
||||
public class DbEmailTemplate
|
||||
{
|
||||
/// <summary>
|
||||
/// 模板ID
|
||||
/// </summary>
|
||||
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模板名称
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 100)]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模板代码(唯一标识)
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 50)]
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模板主题
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 500)]
|
||||
public string Subject { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模板内容
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 4000)]
|
||||
public string Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否为HTML格式
|
||||
/// </summary>
|
||||
public bool IsHtml { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用
|
||||
/// </summary>
|
||||
public bool IsActive { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreatedAt { get; set; } = DateTime.Now;
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.Now;
|
||||
}
|
||||
}
|
||||
@@ -37,5 +37,10 @@ public class MappingProfile : Profile
|
||||
CreateMap<DbNlog, Nlog>().ReverseMap();
|
||||
|
||||
CreateMap<DbVariableHistory, VariableHistory>().ReverseMap();
|
||||
|
||||
CreateMap<DbEmailAccount, EmailAccount>().ReverseMap();
|
||||
CreateMap<DbEmailMessage, EmailMessage>().ReverseMap();
|
||||
CreateMap<DbEmailLog, EmailLog>().ReverseMap();
|
||||
CreateMap<DbEmailTemplate, EmailTemplate>().ReverseMap();
|
||||
}
|
||||
}
|
||||
|
||||
158
DMS.Infrastructure/Repositories/EmailAccountRepository.cs
Normal file
158
DMS.Infrastructure/Repositories/EmailAccountRepository.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
using AutoMapper;
|
||||
using DMS.Core.Interfaces.Repositories;
|
||||
using DMS.Core.Models;
|
||||
using DMS.Infrastructure.Data;
|
||||
using DMS.Infrastructure.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SqlSugar;
|
||||
|
||||
namespace DMS.Infrastructure.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// 邮件账户仓储实现
|
||||
/// </summary>
|
||||
public class EmailAccountRepository : IEmailAccountRepository
|
||||
{
|
||||
private readonly SqlSugarDbContext _dbContext;
|
||||
protected readonly ILogger<EmailAccountRepository> _logger;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public EmailAccountRepository(IMapper mapper, SqlSugarDbContext dbContext, ILogger<EmailAccountRepository> logger)
|
||||
{
|
||||
_mapper = mapper;
|
||||
_dbContext = dbContext;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 SqlSugarClient 实例
|
||||
/// </summary>
|
||||
protected SqlSugarClient Db
|
||||
{
|
||||
get { return _dbContext.GetInstance(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取默认邮件账户
|
||||
/// </summary>
|
||||
public async Task<EmailAccount> GetDefaultAccountAsync()
|
||||
{
|
||||
var dbEntity = await Db.Queryable<DbEmailAccount>()
|
||||
.Where(e => e.IsDefault && e.IsActive)
|
||||
.FirstAsync();
|
||||
|
||||
return dbEntity != null ? _mapper.Map<EmailAccount>(dbEntity) : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有启用的邮件账户
|
||||
/// </summary>
|
||||
public async Task<List<EmailAccount>> GetActiveAccountsAsync()
|
||||
{
|
||||
var dbEntities = await Db.Queryable<DbEmailAccount>()
|
||||
.Where(e => e.IsActive)
|
||||
.ToListAsync();
|
||||
|
||||
return _mapper.Map<List<EmailAccount>>(dbEntities);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据ID获取单个实体。
|
||||
/// </summary>
|
||||
public async Task<EmailAccount> GetByIdAsync(int id)
|
||||
{
|
||||
var dbEntity = await Db.Queryable<DbEmailAccount>()
|
||||
.In(id)
|
||||
.FirstAsync();
|
||||
|
||||
return dbEntity != null ? _mapper.Map<EmailAccount>(dbEntity) : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取所有实体。
|
||||
/// </summary>
|
||||
public async Task<List<EmailAccount>> GetAllAsync()
|
||||
{
|
||||
var dbEntities = await Db.Queryable<DbEmailAccount>()
|
||||
.ToListAsync();
|
||||
|
||||
return _mapper.Map<List<EmailAccount>>(dbEntities);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步添加一个新实体。
|
||||
/// </summary>
|
||||
public async Task<EmailAccount> AddAsync(EmailAccount entity)
|
||||
{
|
||||
var dbEntity = _mapper.Map<DbEmailAccount>(entity);
|
||||
var result = await Db.Insertable(dbEntity)
|
||||
.ExecuteReturnEntityAsync();
|
||||
|
||||
return _mapper.Map<EmailAccount>(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步更新一个已存在的实体。
|
||||
/// </summary>
|
||||
public async Task<int> UpdateAsync(EmailAccount entity)
|
||||
{
|
||||
var dbEntity = _mapper.Map<DbEmailAccount>(entity);
|
||||
return await Db.Updateable(dbEntity)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据ID删除一个实体。
|
||||
/// </summary>
|
||||
public async Task<int> DeleteAsync(EmailAccount entity)
|
||||
{
|
||||
var dbEntity = _mapper.Map<DbEmailAccount>(entity);
|
||||
return await Db.Deleteable(dbEntity)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据ID删除一个实体。
|
||||
/// </summary>
|
||||
public async Task<int> DeleteByIdAsync(int id)
|
||||
{
|
||||
return await Db.Deleteable<DbEmailAccount>()
|
||||
.In(id)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据ID列表批量删除实体。
|
||||
/// </summary>
|
||||
public async Task<int> DeleteByIdsAsync(List<int> ids)
|
||||
{
|
||||
return await Db.Deleteable<DbEmailAccount>()
|
||||
.In(ids)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从数据库获取数据。
|
||||
/// </summary>
|
||||
public async Task<List<EmailAccount>> TakeAsync(int number)
|
||||
{
|
||||
var dbEntities = await Db.Queryable<DbEmailAccount>()
|
||||
.Take(number)
|
||||
.ToListAsync();
|
||||
|
||||
return _mapper.Map<List<EmailAccount>>(dbEntities);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步批量添加实体。
|
||||
/// </summary>
|
||||
public async Task<bool> AddBatchAsync(List<EmailAccount> entities)
|
||||
{
|
||||
var dbEntities = _mapper.Map<List<DbEmailAccount>>(entities);
|
||||
var result = await Db.Insertable(dbEntities)
|
||||
.ExecuteCommandAsync();
|
||||
|
||||
return result > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
158
DMS.Infrastructure/Repositories/EmailLogRepository.cs
Normal file
158
DMS.Infrastructure/Repositories/EmailLogRepository.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
using AutoMapper;
|
||||
using DMS.Core.Interfaces.Repositories;
|
||||
using DMS.Core.Models;
|
||||
using DMS.Infrastructure.Data;
|
||||
using DMS.Infrastructure.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SqlSugar;
|
||||
|
||||
namespace DMS.Infrastructure.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// 邮件日志仓储实现
|
||||
/// </summary>
|
||||
public class EmailLogRepository : IEmailLogRepository
|
||||
{
|
||||
private readonly SqlSugarDbContext _dbContext;
|
||||
protected readonly ILogger<EmailLogRepository> _logger;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public EmailLogRepository(IMapper mapper, SqlSugarDbContext dbContext, ILogger<EmailLogRepository> logger)
|
||||
{
|
||||
_mapper = mapper;
|
||||
_dbContext = dbContext;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 SqlSugarClient 实例
|
||||
/// </summary>
|
||||
protected SqlSugarClient Db
|
||||
{
|
||||
get { return _dbContext.GetInstance(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据ID获取单个实体。
|
||||
/// </summary>
|
||||
public async Task<EmailLog> GetByIdAsync(int id)
|
||||
{
|
||||
var dbEntity = await Db.Queryable<DbEmailLog>()
|
||||
.In(id)
|
||||
.FirstAsync();
|
||||
|
||||
return dbEntity != null ? _mapper.Map<EmailLog>(dbEntity) : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取所有实体。
|
||||
/// </summary>
|
||||
public async Task<List<EmailLog>> GetAllAsync()
|
||||
{
|
||||
var dbEntities = await Db.Queryable<DbEmailLog>()
|
||||
.ToListAsync();
|
||||
|
||||
return _mapper.Map<List<EmailLog>>(dbEntities);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步添加一个新实体。
|
||||
/// </summary>
|
||||
public async Task<EmailLog> AddAsync(EmailLog entity)
|
||||
{
|
||||
var dbEntity = _mapper.Map<DbEmailLog>(entity);
|
||||
var result = await Db.Insertable(dbEntity)
|
||||
.ExecuteReturnEntityAsync();
|
||||
|
||||
return _mapper.Map<EmailLog>(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步更新一个已存在的实体。
|
||||
/// </summary>
|
||||
public async Task<int> UpdateAsync(EmailLog entity)
|
||||
{
|
||||
var dbEntity = _mapper.Map<DbEmailLog>(entity);
|
||||
return await Db.Updateable(dbEntity)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据ID删除一个实体。
|
||||
/// </summary>
|
||||
public async Task<int> DeleteAsync(EmailLog entity)
|
||||
{
|
||||
var dbEntity = _mapper.Map<DbEmailLog>(entity);
|
||||
return await Db.Deleteable(dbEntity)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据ID删除一个实体。
|
||||
/// </summary>
|
||||
public async Task<int> DeleteByIdAsync(int id)
|
||||
{
|
||||
return await Db.Deleteable<DbEmailLog>()
|
||||
.In(id)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据ID列表批量删除实体。
|
||||
/// </summary>
|
||||
public async Task<int> DeleteByIdsAsync(List<int> ids)
|
||||
{
|
||||
return await Db.Deleteable<DbEmailLog>()
|
||||
.In(ids)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从数据库获取数据。
|
||||
/// </summary>
|
||||
public async Task<List<EmailLog>> TakeAsync(int number)
|
||||
{
|
||||
var dbEntities = await Db.Queryable<DbEmailLog>()
|
||||
.Take(number)
|
||||
.ToListAsync();
|
||||
|
||||
return _mapper.Map<List<EmailLog>>(dbEntities);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步批量添加实体。
|
||||
/// </summary>
|
||||
public async Task<bool> AddBatchAsync(List<EmailLog> entities)
|
||||
{
|
||||
var dbEntities = _mapper.Map<List<DbEmailLog>>(entities);
|
||||
var result = await Db.Insertable(dbEntities)
|
||||
.ExecuteCommandAsync();
|
||||
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据邮件消息ID获取日志
|
||||
/// </summary>
|
||||
public async Task<List<EmailLog>> GetByEmailMessageIdAsync(int emailMessageId)
|
||||
{
|
||||
var dbEntities = await Db.Queryable<DbEmailLog>()
|
||||
.Where(e => e.EmailMessageId == emailMessageId)
|
||||
.ToListAsync();
|
||||
|
||||
return _mapper.Map<List<EmailLog>>(dbEntities);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据日期范围获取日志
|
||||
/// </summary>
|
||||
public async Task<List<EmailLog>> GetByDateRangeAsync(DateTime startDate, DateTime endDate)
|
||||
{
|
||||
var dbEntities = await Db.Queryable<DbEmailLog>()
|
||||
.Where(e => e.CreatedAt >= startDate && e.CreatedAt <= endDate)
|
||||
.ToListAsync();
|
||||
|
||||
return _mapper.Map<List<EmailLog>>(dbEntities);
|
||||
}
|
||||
}
|
||||
}
|
||||
158
DMS.Infrastructure/Repositories/EmailMessageRepository.cs
Normal file
158
DMS.Infrastructure/Repositories/EmailMessageRepository.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
using AutoMapper;
|
||||
using DMS.Core.Interfaces.Repositories;
|
||||
using DMS.Core.Models;
|
||||
using DMS.Infrastructure.Data;
|
||||
using DMS.Infrastructure.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SqlSugar;
|
||||
|
||||
namespace DMS.Infrastructure.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// 邮件消息仓储实现
|
||||
/// </summary>
|
||||
public class EmailMessageRepository : IEmailMessageRepository
|
||||
{
|
||||
private readonly SqlSugarDbContext _dbContext;
|
||||
protected readonly ILogger<EmailMessageRepository> _logger;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public EmailMessageRepository(IMapper mapper, SqlSugarDbContext dbContext, ILogger<EmailMessageRepository> logger)
|
||||
{
|
||||
_mapper = mapper;
|
||||
_dbContext = dbContext;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 SqlSugarClient 实例
|
||||
/// </summary>
|
||||
protected SqlSugarClient Db
|
||||
{
|
||||
get { return _dbContext.GetInstance(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据ID获取单个实体。
|
||||
/// </summary>
|
||||
public async Task<EmailMessage> GetByIdAsync(int id)
|
||||
{
|
||||
var dbEntity = await Db.Queryable<DbEmailMessage>()
|
||||
.In(id)
|
||||
.FirstAsync();
|
||||
|
||||
return dbEntity != null ? _mapper.Map<EmailMessage>(dbEntity) : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取所有实体。
|
||||
/// </summary>
|
||||
public async Task<List<EmailMessage>> GetAllAsync()
|
||||
{
|
||||
var dbEntities = await Db.Queryable<DbEmailMessage>()
|
||||
.ToListAsync();
|
||||
|
||||
return _mapper.Map<List<EmailMessage>>(dbEntities);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步添加一个新实体。
|
||||
/// </summary>
|
||||
public async Task<EmailMessage> AddAsync(EmailMessage entity)
|
||||
{
|
||||
var dbEntity = _mapper.Map<DbEmailMessage>(entity);
|
||||
var result = await Db.Insertable(dbEntity)
|
||||
.ExecuteReturnEntityAsync();
|
||||
|
||||
return _mapper.Map<EmailMessage>(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步更新一个已存在的实体。
|
||||
/// </summary>
|
||||
public async Task<int> UpdateAsync(EmailMessage entity)
|
||||
{
|
||||
var dbEntity = _mapper.Map<DbEmailMessage>(entity);
|
||||
return await Db.Updateable(dbEntity)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据ID删除一个实体。
|
||||
/// </summary>
|
||||
public async Task<int> DeleteAsync(EmailMessage entity)
|
||||
{
|
||||
var dbEntity = _mapper.Map<DbEmailMessage>(entity);
|
||||
return await Db.Deleteable(dbEntity)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据ID删除一个实体。
|
||||
/// </summary>
|
||||
public async Task<int> DeleteByIdAsync(int id)
|
||||
{
|
||||
return await Db.Deleteable<DbEmailMessage>()
|
||||
.In(id)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据ID列表批量删除实体。
|
||||
/// </summary>
|
||||
public async Task<int> DeleteByIdsAsync(List<int> ids)
|
||||
{
|
||||
return await Db.Deleteable<DbEmailMessage>()
|
||||
.In(ids)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从数据库获取数据。
|
||||
/// </summary>
|
||||
public async Task<List<EmailMessage>> TakeAsync(int number)
|
||||
{
|
||||
var dbEntities = await Db.Queryable<DbEmailMessage>()
|
||||
.Take(number)
|
||||
.ToListAsync();
|
||||
|
||||
return _mapper.Map<List<EmailMessage>>(dbEntities);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步批量添加实体。
|
||||
/// </summary>
|
||||
public async Task<bool> AddBatchAsync(List<EmailMessage> entities)
|
||||
{
|
||||
var dbEntities = _mapper.Map<List<DbEmailMessage>>(entities);
|
||||
var result = await Db.Insertable(dbEntities)
|
||||
.ExecuteCommandAsync();
|
||||
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据状态获取邮件消息
|
||||
/// </summary>
|
||||
public async Task<List<EmailMessage>> GetByStatusAsync(EmailSendStatus status)
|
||||
{
|
||||
var dbEntities = await Db.Queryable<DbEmailMessage>()
|
||||
.Where(e => e.Status == status.ToString())
|
||||
.ToListAsync();
|
||||
|
||||
return _mapper.Map<List<EmailMessage>>(dbEntities);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定时间范围内的邮件消息
|
||||
/// </summary>
|
||||
public async Task<List<EmailMessage>> GetByDateRangeAsync(DateTime startDate, DateTime endDate)
|
||||
{
|
||||
var dbEntities = await Db.Queryable<DbEmailMessage>()
|
||||
.Where(e => e.CreatedAt >= startDate && e.CreatedAt <= endDate)
|
||||
.ToListAsync();
|
||||
|
||||
return _mapper.Map<List<EmailMessage>>(dbEntities);
|
||||
}
|
||||
}
|
||||
}
|
||||
158
DMS.Infrastructure/Repositories/EmailTemplateRepository.cs
Normal file
158
DMS.Infrastructure/Repositories/EmailTemplateRepository.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
using AutoMapper;
|
||||
using DMS.Core.Interfaces.Repositories;
|
||||
using DMS.Core.Models;
|
||||
using DMS.Infrastructure.Data;
|
||||
using DMS.Infrastructure.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SqlSugar;
|
||||
|
||||
namespace DMS.Infrastructure.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// 邮件模板仓储实现
|
||||
/// </summary>
|
||||
public class EmailTemplateRepository : IEmailTemplateRepository
|
||||
{
|
||||
private readonly SqlSugarDbContext _dbContext;
|
||||
protected readonly ILogger<EmailTemplateRepository> _logger;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public EmailTemplateRepository(IMapper mapper, SqlSugarDbContext dbContext, ILogger<EmailTemplateRepository> logger)
|
||||
{
|
||||
_mapper = mapper;
|
||||
_dbContext = dbContext;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 SqlSugarClient 实例
|
||||
/// </summary>
|
||||
protected SqlSugarClient Db
|
||||
{
|
||||
get { return _dbContext.GetInstance(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据ID获取单个实体。
|
||||
/// </summary>
|
||||
public async Task<EmailTemplate> GetByIdAsync(int id)
|
||||
{
|
||||
var dbEntity = await Db.Queryable<DbEmailTemplate>()
|
||||
.In(id)
|
||||
.FirstAsync();
|
||||
|
||||
return dbEntity != null ? _mapper.Map<EmailTemplate>(dbEntity) : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取所有实体。
|
||||
/// </summary>
|
||||
public async Task<List<EmailTemplate>> GetAllAsync()
|
||||
{
|
||||
var dbEntities = await Db.Queryable<DbEmailTemplate>()
|
||||
.ToListAsync();
|
||||
|
||||
return _mapper.Map<List<EmailTemplate>>(dbEntities);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步添加一个新实体。
|
||||
/// </summary>
|
||||
public async Task<EmailTemplate> AddAsync(EmailTemplate entity)
|
||||
{
|
||||
var dbEntity = _mapper.Map<DbEmailTemplate>(entity);
|
||||
var result = await Db.Insertable(dbEntity)
|
||||
.ExecuteReturnEntityAsync();
|
||||
|
||||
return _mapper.Map<EmailTemplate>(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步更新一个已存在的实体。
|
||||
/// </summary>
|
||||
public async Task<int> UpdateAsync(EmailTemplate entity)
|
||||
{
|
||||
var dbEntity = _mapper.Map<DbEmailTemplate>(entity);
|
||||
return await Db.Updateable(dbEntity)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据ID删除一个实体。
|
||||
/// </summary>
|
||||
public async Task<int> DeleteAsync(EmailTemplate entity)
|
||||
{
|
||||
var dbEntity = _mapper.Map<DbEmailTemplate>(entity);
|
||||
return await Db.Deleteable(dbEntity)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据ID删除一个实体。
|
||||
/// </summary>
|
||||
public async Task<int> DeleteByIdAsync(int id)
|
||||
{
|
||||
return await Db.Deleteable<DbEmailTemplate>()
|
||||
.In(id)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据ID列表批量删除实体。
|
||||
/// </summary>
|
||||
public async Task<int> DeleteByIdsAsync(List<int> ids)
|
||||
{
|
||||
return await Db.Deleteable<DbEmailTemplate>()
|
||||
.In(ids)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从数据库获取数据。
|
||||
/// </summary>
|
||||
public async Task<List<EmailTemplate>> TakeAsync(int number)
|
||||
{
|
||||
var dbEntities = await Db.Queryable<DbEmailTemplate>()
|
||||
.Take(number)
|
||||
.ToListAsync();
|
||||
|
||||
return _mapper.Map<List<EmailTemplate>>(dbEntities);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步批量添加实体。
|
||||
/// </summary>
|
||||
public async Task<bool> AddBatchAsync(List<EmailTemplate> entities)
|
||||
{
|
||||
var dbEntities = _mapper.Map<List<DbEmailTemplate>>(entities);
|
||||
var result = await Db.Insertable(dbEntities)
|
||||
.ExecuteCommandAsync();
|
||||
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据代码获取邮件模板
|
||||
/// </summary>
|
||||
public async Task<EmailTemplate> GetByCodeAsync(string code)
|
||||
{
|
||||
var dbEntity = await Db.Queryable<DbEmailTemplate>()
|
||||
.Where(e => e.Code == code && e.IsActive)
|
||||
.FirstAsync();
|
||||
|
||||
return dbEntity != null ? _mapper.Map<EmailTemplate>(dbEntity) : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有启用的邮件模板
|
||||
/// </summary>
|
||||
public async Task<List<EmailTemplate>> GetActiveTemplatesAsync()
|
||||
{
|
||||
var dbEntities = await Db.Queryable<DbEmailTemplate>()
|
||||
.Where(e => e.IsActive)
|
||||
.ToListAsync();
|
||||
|
||||
return _mapper.Map<List<EmailTemplate>>(dbEntities);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,11 @@ public class InitializeRepository : IInitializeRepository
|
||||
_db.CodeFirst.InitTables<DbMqttServer>();
|
||||
_db.CodeFirst.InitTables<DbVariableMqttAlias>();
|
||||
_db.CodeFirst.InitTables<DbMenu>();
|
||||
_db.CodeFirst.InitTables<DbNlog>();
|
||||
_db.CodeFirst.InitTables<DbEmailAccount>();
|
||||
_db.CodeFirst.InitTables<DbEmailMessage>();
|
||||
_db.CodeFirst.InitTables<DbEmailTemplate>();
|
||||
_db.CodeFirst.InitTables<DbEmailLog>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -140,14 +145,20 @@ public class InitializeRepository : IInitializeRepository
|
||||
},
|
||||
new DbMenu
|
||||
{
|
||||
Id = 6, Header = "设置", Icon = "\uE713", ParentId = 0,
|
||||
MenuType = MenuType.MainMenu, TargetViewKey = "SettingView",
|
||||
Id = 6, Header = "邮件管理", Icon = "\uE715", ParentId = 0,
|
||||
MenuType = MenuType.MainMenu, TargetViewKey = "EmailManagementView",
|
||||
DisplayOrder = 6
|
||||
},
|
||||
new DbMenu
|
||||
{
|
||||
Id = 7, Header = "关于", Icon = "\uE946", ParentId = 0,
|
||||
MenuType = MenuType.MainMenu, TargetViewKey = "", DisplayOrder = 7
|
||||
Id = 7, Header = "设置", Icon = "\uE713", ParentId = 0,
|
||||
MenuType = MenuType.MainMenu, TargetViewKey = "SettingView",
|
||||
DisplayOrder = 7
|
||||
},
|
||||
new DbMenu
|
||||
{
|
||||
Id = 8, Header = "关于", Icon = "\uE946", ParentId = 0,
|
||||
MenuType = MenuType.MainMenu, TargetViewKey = "", DisplayOrder = 8
|
||||
} // 假设有一个AboutView
|
||||
};
|
||||
|
||||
|
||||
170
DMS.Infrastructure/Services/EmailService.cs
Normal file
170
DMS.Infrastructure/Services/EmailService.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
using DMS.Core.Interfaces.Services;
|
||||
using DMS.Core.Models;
|
||||
using MailKit.Net.Imap;
|
||||
using MailKit.Net.Smtp;
|
||||
using MailKit.Security;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MimeKit;
|
||||
|
||||
namespace DMS.Infrastructure.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// 邮件服务实现
|
||||
/// </summary>
|
||||
public class EmailService : IEmailService
|
||||
{
|
||||
private readonly ILogger<EmailService> _logger;
|
||||
|
||||
public EmailService(ILogger<EmailService> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送邮件
|
||||
/// </summary>
|
||||
public async Task<bool> SendEmailAsync(EmailMessage message, EmailAccount account)
|
||||
{
|
||||
try
|
||||
{
|
||||
var mimeMessage = new MimeMessage();
|
||||
mimeMessage.From.Add(new MailboxAddress(account.EmailAddress, account.EmailAddress));
|
||||
mimeMessage.To.AddRange(ParseAddresses(message.To));
|
||||
|
||||
if (!string.IsNullOrEmpty(message.Cc))
|
||||
mimeMessage.Cc.AddRange(ParseAddresses(message.Cc));
|
||||
|
||||
if (!string.IsNullOrEmpty(message.Bcc))
|
||||
mimeMessage.Bcc.AddRange(ParseAddresses(message.Bcc));
|
||||
|
||||
mimeMessage.Subject = message.Subject;
|
||||
|
||||
var bodyBuilder = new BodyBuilder();
|
||||
if (message.IsHtml)
|
||||
bodyBuilder.HtmlBody = message.Body;
|
||||
else
|
||||
bodyBuilder.TextBody = message.Body;
|
||||
|
||||
mimeMessage.Body = bodyBuilder.ToMessageBody();
|
||||
|
||||
using var client = new SmtpClient();
|
||||
await client.ConnectAsync(account.SmtpServer, account.SmtpPort, account.EnableSsl ? SecureSocketOptions.SslOnConnect : SecureSocketOptions.None);
|
||||
await client.AuthenticateAsync(account.Username, account.Password);
|
||||
await client.SendAsync(mimeMessage);
|
||||
await client.DisconnectAsync(true);
|
||||
|
||||
message.Status = EmailSendStatus.Sent;
|
||||
message.SentAt = DateTime.Now;
|
||||
|
||||
_logger.LogInformation($"邮件发送成功: {message.Subject}");
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
message.Status = EmailSendStatus.Failed;
|
||||
_logger.LogError(ex, $"邮件发送失败: {message.Subject}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步接收邮件
|
||||
/// </summary>
|
||||
public async Task<List<EmailMessage>> ReceiveEmailsAsync(EmailAccount account, int count = 10)
|
||||
{
|
||||
var emails = new List<EmailMessage>();
|
||||
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(account.ImapServer))
|
||||
{
|
||||
_logger.LogWarning("未配置IMAP服务器,无法接收邮件");
|
||||
return emails;
|
||||
}
|
||||
|
||||
using var client = new ImapClient();
|
||||
await client.ConnectAsync(account.ImapServer, account.ImapPort, SecureSocketOptions.SslOnConnect);
|
||||
await client.AuthenticateAsync(account.Username, account.Password);
|
||||
|
||||
var inbox = client.Inbox;
|
||||
await inbox.OpenAsync(MailKit.FolderAccess.ReadOnly);
|
||||
|
||||
var endIndex = Math.Min(count, inbox.Count);
|
||||
for (int i = 0; i < endIndex; i++)
|
||||
{
|
||||
var message = await inbox.GetMessageAsync(i);
|
||||
var email = new EmailMessage
|
||||
{
|
||||
EmailAccountId = account.Id,
|
||||
From = message.From.ToString(),
|
||||
To = message.To.ToString(),
|
||||
Subject = message.Subject,
|
||||
Body = message.TextBody ?? message.HtmlBody ?? "",
|
||||
IsHtml = !string.IsNullOrEmpty(message.HtmlBody),
|
||||
SentAt = message.Date.DateTime,
|
||||
CreatedAt = DateTime.Now,
|
||||
UpdatedAt = DateTime.Now
|
||||
};
|
||||
emails.Add(email);
|
||||
}
|
||||
|
||||
await client.DisconnectAsync(true);
|
||||
_logger.LogInformation($"成功接收 {emails.Count} 封邮件");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "接收邮件时发生错误");
|
||||
}
|
||||
|
||||
return emails;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试邮件账户连接
|
||||
/// </summary>
|
||||
public async Task<bool> TestConnectionAsync(EmailAccount account)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 测试SMTP连接
|
||||
using var smtpClient = new SmtpClient();
|
||||
await smtpClient.ConnectAsync(account.SmtpServer, account.SmtpPort, account.EnableSsl ? SecureSocketOptions.SslOnConnect : SecureSocketOptions.None);
|
||||
await smtpClient.AuthenticateAsync(account.Username, account.Password);
|
||||
await smtpClient.DisconnectAsync(true);
|
||||
|
||||
// 如果配置了IMAP服务器,也测试IMAP连接
|
||||
if (!string.IsNullOrEmpty(account.ImapServer))
|
||||
{
|
||||
using var imapClient = new ImapClient();
|
||||
await imapClient.ConnectAsync(account.ImapServer, account.ImapPort, SecureSocketOptions.SslOnConnect);
|
||||
await imapClient.AuthenticateAsync(account.Username, account.Password);
|
||||
await imapClient.DisconnectAsync(true);
|
||||
}
|
||||
|
||||
_logger.LogInformation($"邮件账户 {account.EmailAddress} 连接测试成功");
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"邮件账户 {account.EmailAddress} 连接测试失败");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析邮箱地址字符串
|
||||
/// </summary>
|
||||
private IEnumerable<MailboxAddress> ParseAddresses(string addresses)
|
||||
{
|
||||
var addressList = addresses.Split(new[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var address in addressList)
|
||||
{
|
||||
var trimmedAddress = address.Trim();
|
||||
if (!string.IsNullOrEmpty(trimmedAddress))
|
||||
{
|
||||
yield return MailboxAddress.Parse(trimmedAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user