Program.cs
安装包:Microsoft.AspNetCore.Hosting.WindowsServices、Microsoft.Extensions.Hosting、Microsoft.Extensions.Hosting.WindowsServices、Microsoft.Extensions.Logging.Log4Net.AspNetCore
新建Configs/log4net.config
using Com.Chinahorn.Exchange.WorkerService;IHost host = Host.CreateDefaultBuilder(args).UseWindowsService().ConfigureLogging(logging => logging.AddLog4Net("Configs/log4net.config")).ConfigureServices(services =>{services.AddHostedService<Worker>();}).Build();await host.RunAsync();
log4net.config
<?xml version="1.0" encoding="utf-8" ?>
<log4net><!-- Define some output appenders --><appender name="rollingAppender" type="log4net.Appender.RollingFileAppender"><!-- value="logs/log.log"--><file value="logs/" /><!--追加日志内容--><appendToFile value="true" /><!--防止多线程时不能写Log,官方说线程非安全--><lockingModel type="log4net.Appender.FileAppender+MinimalLock" /><!--可以为:Once|Size|Date|Composite--><!--Composite为Size和Date的组合--><rollingStyle value="Composite" /><!--当备份文件时,为文件名加的后缀--><datePattern value="yyyyMMddhh'.log'" /><!--日志最大个数,都是最新的--><!--rollingStyle节点为Size时,只能有value个日志--><!--rollingStyle节点为Composite时,每天有value个日志--><maxSizeRollBackups value="20" /><!--可用的单位:KB|MB|GB--><maximumFileSize value="3MB" /><!--置为true,当前最新日志文件名永远为file节中的名字--><staticLogFileName value="false" /><!--输出级别在INFO和ERROR之间的日志--><filter type="log4net.Filter.LevelRangeFilter"><param name="LevelMin" value="ALL" /><param name="LevelMax" value="FATAL" /></filter><layout type="log4net.Layout.PatternLayout"><conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/></layout></appender><root><!--控制级别,由低到高: ALL|DEBUG|INFO|WARN|ERROR|FATAL|OFF--><!--OFF:0--><!--FATAL:FATAL--><!--ERROR: ERROR,FATAL--><!--WARN: WARN,ERROR,FATAL--><!--INFO: INFO,WARN,ERROR,FATAL--><!--DEBUG: INFO,WARN,ERROR,FATAL--><!--ALL: DEBUG,INFO,WARN,ERROR,FATAL--><priority value="ALL"/><level value="INFO"/><!--使用上面配置的那个规则,ref指定上面的规则名称--><appender-ref ref="rollingAppender" /></root>
</log4net>
Worker.cs
namespace Com.Chinahorn.Exchange.WorkerService
{public class Worker : BackgroundService{private readonly ILogger<Worker> _logger;public Worker(ILogger<Worker> logger){_logger = logger;}protected override async Task ExecuteAsync(CancellationToken stoppingToken){while (!stoppingToken.IsCancellationRequested){_logger.LogInformation("Com.Chinahorn.Exchange.Service Worker running Start: {time}", DateTimeOffset.Now);IConfiguration configuration = new ConfigurationBuilder().SetBasePath(AppDomain.CurrentDomain.BaseDirectory).AddJsonFile("appsettings.json").Build();try{ExchangeMailFind exchangeMail = new ExchangeMailFind(_logger);exchangeMail.doWork();}catch (Exception ex){_logger.LogError("Com.Chinahorn.Exchange.Service Worker error: {ex}", ex);}_logger.LogInformation("Com.Chinahorn.Exchange.Service Worker running End : {time}", DateTimeOffset.Now);int workSplit = Convert.ToInt32(configuration.GetConnectionString("workSplit"));//workSplit = workSplit <= 5 ? 5 : workSplit;await Task.Delay(workSplit * 1000, stoppingToken);}}}
}
ExchangeMailFind.cs
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Web;
using Com.Chinahorn.Exchange.DBHelper;
using Com.Chinahorn.Exchange.WorkerService;
using Microsoft.Exchange.WebServices.Data;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;public class ExchangeMailFind
{private readonly ILogger<Worker> _logger;public ExchangeMailFind(ILogger<Worker> logger){_logger = logger;}public void doWork(){IConfiguration configuration = new ConfigurationBuilder().SetBasePath(AppDomain.CurrentDomain.BaseDirectory).AddJsonFile("appsettings.json").Build();string[] exchangeUrl = configuration.GetConnectionString("EWSUrl").Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);string[] username = configuration.GetConnectionString("MailUserName").Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);string[] password = configuration.GetConnectionString("MailPWD").Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);string[] MailDateFilter = configuration.GetConnectionString("MailDateFilter").Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);if (exchangeUrl.Length != username.Length && username.Length != password.Length && password.Length != MailDateFilter.Length){_logger.LogInformation("配置信息:EWSUrl、MailUserName、MailPWD设置有误,多套需对应设置");return;}int pagerSize = Convert.ToInt32(configuration.GetConnectionString("MailPagerSize"));SQLHelper db_helper = new SQLHelper();for (int k = 0; k < exchangeUrl.Length; k++){try{ServicePointManager.ServerCertificateValidationCallback = (RemoteCertificateValidationCallback)Delegate.Combine(ServicePointManager.ServerCertificateValidationCallback, (RemoteCertificateValidationCallback)((object sender, X509Certificate? cert, X509Chain? chain, SslPolicyErrors sslPolicyErrors) => true));ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);service.Url = new Uri(exchangeUrl[k]);string pwd = password[k];service.Credentials = new WebCredentials(username[k], pwd);_logger.LogInformation("doWork ExchangeService EWSUrl:" + exchangeUrl[k] + " 凭据验证成功");DateTime startDate = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd"));if (MailDateFilter.Length > 0 && !string.IsNullOrWhiteSpace(MailDateFilter[k])){startDate = Convert.ToDateTime(MailDateFilter[k]);}SearchFilter.IsGreaterThanOrEqualTo timeFilter = new SearchFilter.IsGreaterThanOrEqualTo(ItemSchema.DateTimeReceived, startDate);ItemView view = new ItemView(pagerSize);view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject, ItemSchema.DateTimeReceived);int offset = 0;//int i = 1;FindItemsResults<Item> findResults;do{view.Offset = offset;findResults = service.FindItems(WellKnownFolderName.Inbox, timeFilter, view);_logger.LogInformation("doWork 获取收件箱Count:" + findResults.Items.Count);foreach (Item item in findResults){EmailMessage email = EmailMessage.Bind(service, item.Id, new PropertySet(BasePropertySet.FirstClassProperties));//Console.WriteLine("序号: " + i);//Console.WriteLine("发件人: " + email.Sender.Name);//Console.WriteLine("发件邮箱: " + email.Sender.Address);//Console.WriteLine("主题: " + email.Subject);//Console.WriteLine("内容: " + email.Body);//Console.WriteLine("发送时间: " + email.DateTimeSent);//Console.WriteLine("收件人: " + email.ReceivedBy.Name);//Console.WriteLine("收件邮箱: " + email.ReceivedBy.Address);string AttachmentName = string.Empty;string AttachmentStream = string.Empty;try{foreach (Attachment attachment in email.Attachments){if (attachment is FileAttachment){FileAttachment fileAttachment = attachment as FileAttachment;Console.WriteLine("附件名称: " + fileAttachment.Name);AttachmentName = AttachmentName + fileAttachment.Name + ";";// 使用内存流读取文件内容using (MemoryStream ms = new MemoryStream()){fileAttachment.Load(ms);byte[] buffer = ms.ToArray();Console.WriteLine("附件文件流: " + Convert.ToBase64String(buffer));AttachmentStream = AttachmentStream + Convert.ToBase64String(buffer) + ";";}}}}catch (Exception ex){_logger.LogError("doWork email.Attachments循环报错:" + ex.Message, ex);}string CcRecipientsMail = string.Empty;foreach (EmailAddress cc in email.CcRecipients){Console.WriteLine("抄送人: " + cc.Address);CcRecipientsMail = CcRecipientsMail + cc.Address + ";";}string messageId = email.InternetMessageHeaders.Find("Message-ID").Value;_logger.LogInformation("doWork Message-ID:" + messageId);//Console.WriteLine("Message-ID:" + messageId); }offset += findResults.Items.Count;Thread.Sleep(1000);}while (findResults.MoreAvailable);}catch (Exception ex){_logger.LogError("doWork exchangeUrl for k:" + k.ToString() + "报错:" + ex.Message, ex);}}}
appsettings.json
{"Logging": {"LogLevel": {"Default": "Information","Microsoft.Hosting.Lifetime": "Information"}},"ConnectionStrings": {"SQLConnStr": "server=.;uid=sa;pwd=xx;database=xx;Encrypt=True;TrustServerCertificate=True;",//Exchange WebService,多套用;标识(多套需对应设置)"EWSUrl": "https://mail.xx.com/EWS/Exchange.asmx",//Exchange用户名,多套用;标识(多套需对应设置)"MailUserName": "xx",//Exchange密码,多套用;标识(多套需对应设置)"MailPWD": "Vm1GbFkyNDNPREl3TWpJeEl5UndZWE56Y0c5eWRBPT0=",//获取特定时间之后的邮件(如果为空则获取当天的),多套用;标识(多套需对应设置)"MailDateFilter": "2024-04-28",//分页获取邮件数"MailPagerSize": "50","WorkSplit": "60" //服务轮询时间,秒}
}