paiban/NPP.SmartSchedue.Api/Services/Notification/EmailNotificationService.cs
Developer 058d8edffa 添加通知系统和工作任务分配功能
- 新增通知系统完整架构,包含通知设置、历史记录、任务管理等核心功能
- 实现工作任务分配服务,支持人员和设备的智能分配
- 添加人员分组管理功能,支持灵活的通知目标配置
- 完善相关枚举定义和数据传输对象

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-05 08:34:01 +08:00

409 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Net.Mail;
using System.Net;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using NPP.SmartSchedue.Api.Contracts.Services.Notification;
namespace NPP.SmartSchedue.Api.Services.Notification;
/// <summary>
/// 邮件通知服务实现
/// 决策点1基础通知方式 - 邮件通知
/// </summary>
public class EmailNotificationService : IEmailNotificationService
{
private readonly ILogger<EmailNotificationService> _logger;
private readonly IConfiguration _configuration;
private readonly INotificationTemplateService _templateService;
// 邮件配置节点名称
private const string EmailConfigSection = "EmailNotification";
public EmailNotificationService(
ILogger<EmailNotificationService> logger,
IConfiguration configuration,
INotificationTemplateService templateService)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
_templateService = templateService ?? throw new ArgumentNullException(nameof(templateService));
}
#region
/// <summary>
/// 发送邮件通知
/// </summary>
public async Task<bool> SendEmailAsync(string recipientEmail, string subject, string content, bool isHtml = true)
{
try
{
if (!IsValidEmail(recipientEmail))
{
_logger.LogWarning("无效的邮箱地址:{Email}", recipientEmail);
return false;
}
var emailConfig = GetEmailConfiguration();
if (emailConfig == null)
{
_logger.LogError("邮件配置未找到或配置无效");
return false;
}
using var smtpClient = CreateSmtpClient(emailConfig);
using var mailMessage = CreateMailMessage(emailConfig, recipientEmail, subject, content, isHtml);
await smtpClient.SendMailAsync(mailMessage);
_logger.LogInformation("邮件发送成功:{Email} - {Subject}", recipientEmail, subject);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "发送邮件失败:{Email} - {Subject}", recipientEmail, subject);
return false;
}
}
/// <summary>
/// 发送邮件通知(带附件)
/// </summary>
public async Task<bool> SendEmailWithAttachmentsAsync(
string recipientEmail,
string subject,
string content,
List<string> attachments,
bool isHtml = true)
{
try
{
if (!IsValidEmail(recipientEmail))
{
_logger.LogWarning("无效的邮箱地址:{Email}", recipientEmail);
return false;
}
var emailConfig = GetEmailConfiguration();
if (emailConfig == null)
{
_logger.LogError("邮件配置未找到或配置无效");
return false;
}
using var smtpClient = CreateSmtpClient(emailConfig);
using var mailMessage = CreateMailMessage(emailConfig, recipientEmail, subject, content, isHtml);
// 添加附件
if (attachments != null && attachments.Any())
{
foreach (var attachmentPath in attachments)
{
if (File.Exists(attachmentPath))
{
var attachment = new Attachment(attachmentPath);
mailMessage.Attachments.Add(attachment);
}
else
{
_logger.LogWarning("附件文件不存在:{Path}", attachmentPath);
}
}
}
await smtpClient.SendMailAsync(mailMessage);
_logger.LogInformation("带附件邮件发送成功:{Email} - {Subject}, 附件数量:{Count}",
recipientEmail, subject, attachments?.Count ?? 0);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "发送带附件邮件失败:{Email} - {Subject}", recipientEmail, subject);
return false;
}
}
#endregion
#region
/// <summary>
/// 批量发送邮件通知
/// </summary>
public async Task<Dictionary<string, bool>> BatchSendEmailAsync(
List<string> recipients,
string subject,
string content,
bool isHtml = true)
{
var results = new Dictionary<string, bool>();
if (recipients == null || !recipients.Any())
{
_logger.LogWarning("批量发送邮件:收件人列表为空");
return results;
}
var emailConfig = GetEmailConfiguration();
if (emailConfig == null)
{
_logger.LogError("邮件配置未找到或配置无效");
foreach (var recipient in recipients)
{
results[recipient] = false;
}
return results;
}
// 并行发送邮件
var tasks = recipients.Select(async recipient =>
{
var success = await SendEmailAsync(recipient, subject, content, isHtml);
return new { Recipient = recipient, Success = success };
});
var taskResults = await Task.WhenAll(tasks);
foreach (var result in taskResults)
{
results[result.Recipient] = result.Success;
}
var successCount = results.Values.Count(r => r);
_logger.LogInformation("批量发送邮件完成:总数 {Total},成功 {Success},失败 {Failed}",
recipients.Count, successCount, recipients.Count - successCount);
return results;
}
/// <summary>
/// 个性化批量发送邮件通知
/// </summary>
public async Task<Dictionary<string, bool>> BatchSendPersonalizedEmailAsync(List<EmailItem> emailItems)
{
var results = new Dictionary<string, bool>();
if (emailItems == null || !emailItems.Any())
{
_logger.LogWarning("个性化批量发送邮件:邮件项列表为空");
return results;
}
var emailConfig = GetEmailConfiguration();
if (emailConfig == null)
{
_logger.LogError("邮件配置未找到或配置无效");
foreach (var item in emailItems)
{
results[item.RecipientEmail] = false;
}
return results;
}
// 并行发送邮件
var tasks = emailItems.Select(async item =>
{
var success = await SendEmailWithAttachmentsAsync(
item.RecipientEmail,
item.Subject,
item.Content,
item.Attachments,
item.IsHtml);
return new { Recipient = item.RecipientEmail, Success = success };
});
var taskResults = await Task.WhenAll(tasks);
foreach (var result in taskResults)
{
results[result.Recipient] = result.Success;
}
var successCount = results.Values.Count(r => r);
_logger.LogInformation("个性化批量发送邮件完成:总数 {Total},成功 {Success},失败 {Failed}",
emailItems.Count, successCount, emailItems.Count - successCount);
return results;
}
#endregion
#region
/// <summary>
/// 使用模板发送邮件
/// </summary>
public async Task<bool> SendEmailByTemplateAsync(
string recipientEmail,
string subjectTemplate,
string contentTemplate,
Dictionary<string, string> variables,
bool isHtml = true)
{
try
{
// 渲染模板
var subject = await _templateService.RenderTemplateAsync(subjectTemplate, variables);
var content = await _templateService.RenderTemplateAsync(contentTemplate, variables);
// 发送邮件
return await SendEmailAsync(recipientEmail, subject, content, isHtml);
}
catch (Exception ex)
{
_logger.LogError(ex, "使用模板发送邮件失败:{Email}", recipientEmail);
return false;
}
}
#endregion
#region
/// <summary>
/// 验证邮箱地址格式
/// </summary>
public bool IsValidEmail(string email)
{
if (string.IsNullOrWhiteSpace(email))
return false;
try
{
// 使用正则表达式验证邮箱格式
var emailRegex = new Regex(
@"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
return emailRegex.IsMatch(email);
}
catch
{
return false;
}
}
/// <summary>
/// 检查邮件服务器连接状态
/// </summary>
public async Task<bool> CheckEmailServerConnectionAsync()
{
try
{
var emailConfig = GetEmailConfiguration();
if (emailConfig == null)
{
_logger.LogError("邮件配置未找到或配置无效");
return false;
}
using var smtpClient = CreateSmtpClient(emailConfig);
// 尝试连接到SMTP服务器
await Task.Run(() =>
{
smtpClient.Connect(emailConfig.SmtpServer, emailConfig.SmtpPort);
smtpClient.Disconnect(true);
});
_logger.LogInformation("邮件服务器连接测试成功:{Server}:{Port}",
emailConfig.SmtpServer, emailConfig.SmtpPort);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "邮件服务器连接测试失败");
return false;
}
}
#endregion
#region
/// <summary>
/// 获取邮件配置
/// </summary>
private EmailConfiguration GetEmailConfiguration()
{
try
{
var config = new EmailConfiguration();
_configuration.GetSection(EmailConfigSection).Bind(config);
// 验证配置
if (string.IsNullOrWhiteSpace(config.SmtpServer) ||
config.SmtpPort <= 0 ||
string.IsNullOrWhiteSpace(config.SenderEmail) ||
string.IsNullOrWhiteSpace(config.SenderPassword))
{
_logger.LogError("邮件配置信息不完整");
return null;
}
return config;
}
catch (Exception ex)
{
_logger.LogError(ex, "获取邮件配置失败");
return null;
}
}
/// <summary>
/// 创建SMTP客户端
/// </summary>
private SmtpClient CreateSmtpClient(EmailConfiguration config)
{
var smtpClient = new SmtpClient(config.SmtpServer, config.SmtpPort)
{
Credentials = new NetworkCredential(config.SenderEmail, config.SenderPassword),
EnableSsl = config.EnableSsl,
DeliveryMethod = SmtpDeliveryMethod.Network,
Timeout = config.TimeoutSeconds * 1000
};
return smtpClient;
}
/// <summary>
/// 创建邮件消息
/// </summary>
private MailMessage CreateMailMessage(EmailConfiguration config, string recipientEmail, string subject, string content, bool isHtml)
{
var mailMessage = new MailMessage
{
From = new MailAddress(config.SenderEmail, config.SenderName),
Subject = subject,
Body = content,
IsBodyHtml = isHtml
};
mailMessage.To.Add(recipientEmail);
return mailMessage;
}
#endregion
/// <summary>
/// 邮件配置类
/// </summary>
private class EmailConfiguration
{
public string SmtpServer { get; set; } = "";
public int SmtpPort { get; set; } = 587;
public string SenderEmail { get; set; } = "";
public string SenderPassword { get; set; } = "";
public string SenderName { get; set; } = "NPP智能生产调度系统";
public bool EnableSsl { get; set; } = true;
public int TimeoutSeconds { get; set; } = 30;
}
}