如何用C#控制台应用追踪用户邮件及开发.NET邮件合规监控系统
解决方案:邮件追踪与内容监控的.NET实现
嘿,针对你提出的两个邮件相关的.NET开发需求,我整理了具体的实现思路和代码示例,希望能帮到你:
一、C#控制台应用实现已发送邮件追踪
要追踪用户已发送的邮件,推荐使用Microsoft Graph API(EWS已逐步被微软弃用,Graph是更优选择),下面是具体实现步骤:
1. 前期准备
- 在Azure AD中注册一个控制台类型的应用,配置
Mail.Read权限(需管理员同意),记录下客户端ID、租户ID、客户端密钥。 - 安装必要的NuGet包:
Install-Package Microsoft.Graph Install-Package Microsoft.Identity.Client
2. 核心代码示例
using Microsoft.Graph; using Microsoft.Identity.Client; using System; using System.Collections.Generic; using System.Threading.Tasks; namespace SentMailTracker { class Program { private static readonly string ClientId = "你的客户端ID"; private static readonly string TenantId = "你的租户ID"; private static readonly string ClientSecret = "你的客户端密钥"; static async Task Main(string[] args) { // 初始化认证提供器 var confidentialClientApplication = ConfidentialClientApplicationBuilder .Create(ClientId) .WithTenantId(TenantId) .WithClientSecret(ClientSecret) .Build(); var authProvider = new ClientCredentialProvider(confidentialClientApplication); var graphClient = new GraphServiceClient(authProvider); try { // 获取已发送邮件(最多100封,可调整参数) var sentMessages = await graphClient.Me.MailFolders.SentItems.Messages .Request() .Select(m => new { m.Subject, m.ToRecipients, m.SentDateTime, m.Id }) .Top(100) .GetAsync(); Console.WriteLine("已发送邮件列表:"); foreach (var message in sentMessages) { Console.WriteLine($"主题:{message.Subject}"); Console.WriteLine($"发送时间:{message.SentDateTime?.ToString("yyyy-MM-dd HH:mm:ss")}"); Console.WriteLine("收件人:"); foreach (var recipient in message.ToRecipients) { Console.WriteLine($" - {recipient.EmailAddress.Name} <{recipient.EmailAddress.Address}>"); } Console.WriteLine("----------------------------------------"); } } catch (Exception ex) { Console.WriteLine($"获取邮件失败:{ex.Message}"); } } } }
3. 注意事项
- 如果要追踪特定用户的邮件,需确保应用有对应的用户权限,或者使用用户认证模式(而非客户端凭证)。
- 可以扩展代码,将邮件信息存储到数据库中,实现长期追踪。
二、.NET应用监控邮件防止工作信息泄露
这个需求需要实现收件人校验、正文敏感检测、附件检查三个核心功能,分两种场景实现:
场景1:事后审计(监控已发送邮件)
基于上面的Graph API代码,扩展检查逻辑即可:
// 在获取到sentMessages后,添加检查逻辑 foreach (var message in sentMessages) { // 1. 检查收件人是否为外部邮箱 bool hasExternalRecipients = HasExternalRecipients(message.ToRecipients, "@yourcompany.com"); // 2. 检查正文敏感内容 bool hasSensitiveContent = await CheckSensitiveBodyContent(graphClient, message.Id); // 3. 检查附件 bool hasSensitiveAttachments = await CheckSensitiveAttachments(graphClient, message.Id); if (hasExternalRecipients || hasSensitiveContent || hasSensitiveAttachments) { Console.WriteLine($"⚠️ 风险邮件:{message.Subject}"); // 这里可以添加告警逻辑,比如发送通知到管理员邮箱 } } // 辅助方法示例 private static bool HasExternalRecipients(IEnumerable<Recipient> recipients, string companyDomain) { foreach (var recipient in recipients) { if (!recipient.EmailAddress.Address.EndsWith(companyDomain, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private static async Task<bool> CheckSensitiveBodyContent(GraphServiceClient graphClient, string messageId) { var message = await graphClient.Me.Messages[messageId].Request().Select(m => m.Body).GetAsync(); string bodyText = message.Body.Content; // 简化示例:检查是否包含敏感关键词 string[] sensitiveKeywords = { "项目机密", "客户数据", "内部文档" }; foreach (var keyword in sensitiveKeywords) { if (bodyText.Contains(keyword)) { return true; } } return false; }
场景2:事前拦截(发送前检查)
如果需要在用户发送邮件前就拦截,推荐开发Outlook VSTO插件,通过订阅ItemSend事件实现:
using Outlook = Microsoft.Office.Interop.Outlook; using System.Windows.Forms; namespace MailMonitorAddIn { public partial class ThisAddIn { private void ThisAddIn_Startup(object sender, System.EventArgs e) { // 订阅邮件发送事件 Application.ItemSend += Application_ItemSend; } private void Application_ItemSend(object Item, ref bool Cancel) { if (Item is Outlook.MailItem mailItem) { bool isRisky = false; string warningMsg = ""; // 检查外部收件人 if (HasExternalRecipients(mailItem.Recipients, "@yourcompany.com")) { warningMsg += "邮件包含外部收件人;"; isRisky = true; } // 检查正文敏感内容 if (CheckSensitiveContent(mailItem.Body)) { warningMsg += "正文包含敏感信息;"; isRisky = true; } // 检查附件 if (CheckSensitiveAttachments(mailItem.Attachments)) { warningMsg += "附件包含敏感内容;"; isRisky = true; } if (isRisky) { MessageBox.Show($"禁止发送:{warningMsg}", "邮件监控告警", MessageBoxButtons.OK, MessageBoxIcon.Warning); Cancel = true; // 取消邮件发送 } } } // 辅助方法实现和之前类似,这里省略 private bool HasExternalRecipients(Outlook.Recipients recipients, string companyDomain) { foreach (Outlook.Recipient recipient in recipients) { if (!recipient.Address.EndsWith(companyDomain, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private bool CheckSensitiveContent(string body) { string[] sensitiveKeywords = { "项目机密", "客户数据" }; foreach (var keyword in sensitiveKeywords) { if (body.Contains(keyword)) { return true; } } return false; } private bool CheckSensitiveAttachments(Outlook.Attachments attachments) { string[] forbiddenExtensions = { ".docx", ".xlsx", ".pdf" }; foreach (Outlook.Attachment attachment in attachments) { string extension = System.IO.Path.GetExtension(attachment.FileName).ToLower(); if (forbiddenExtensions.Contains(extension)) { return true; } } return false; } private void ThisAddIn_Shutdown(object sender, System.EventArgs e) { // 清理资源 } #region VSTO generated code private void InternalStartup() { this.Startup += new System.EventHandler(ThisAddIn_Startup); this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown); } #endregion } }
注意事项
- 敏感信息检测可以进一步优化,比如使用正则表达式匹配更复杂的模式,或者集成内容安全服务提升准确率。
- VSTO插件需要部署到用户的Outlook客户端,适合企业内部场景。
内容的提问来源于stack exchange,提问作者Magdy Ismail
相关产品推荐
相关产品推荐

