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" //服务轮询时间,秒
}
}