private async Task ProcessTaskItemsAsync(EmailMassSendingTaskContext context, ICollection <EmailMassSendingTaskItem> items, CancellationToken cancellationToken) { if (!items.Any()) { return; } var delay = _configuration.DelayBetweenSendsInThread ?? TimeSpan.Zero; var lastItem = items.Last(); foreach (var item in items) { if (cancellationToken.IsCancellationRequested) { return; } await ProcessTaskItemAsync(context, item, cancellationToken); if (item != lastItem) { await Task.Delay(delay, cancellationToken); } } }
private async Task ProcessTaskItemAsync(EmailMassSendingTaskContext context, EmailMassSendingTaskItem item, CancellationToken cancellationToken) { item.AttemptsLeft--; item.Attempt = DateTimeOffset.UtcNow; var defaultEncoding = _configuration.Encoding == null ? Encoding.UTF8 : Encoding.GetEncoding(_configuration.Encoding); var encoding = context.GroupConfiguration.Encoding == null ? defaultEncoding : Encoding.GetEncoding(context.GroupConfiguration.Encoding); //using var client = new SmtpClient() var scope = _logger.BeginScope(context.TaskId); if (_configuration.SmtpClient.Enable ?? true) { try { using var client = new SmtpClient(); client.Host = _configuration.SmtpClient.Host; client.Port = _configuration.SmtpClient.Port ?? 25; client.EnableSsl = _configuration.SmtpClient.UseSsl ?? true; client.DeliveryMethod = SmtpDeliveryMethod.Network; client.UseDefaultCredentials = false; client.Credentials = new NetworkCredential(_configuration.SmtpClient.Username, _configuration.SmtpClient.Password); using var message = new MailMessage(); message.From = new MailAddress(_configuration.FromAddress, _configuration.FromTitle, defaultEncoding); message.BodyEncoding = encoding; message.SubjectEncoding = encoding; message.IsBodyHtml = false; message.Body = encoding.GetString(context.Text); message.Subject = context.GroupConfiguration.Subject; message.To.Add(new MailAddress(item.Receiver)); var ts = DateTime.UtcNow; await client.SendMailAsync(message, cancellationToken); _logger.LogDebug( $"Mail to `{item.Receiver}` sent ({DateTime.UtcNow.Subtract(ts).TotalSeconds} s)."); item.Failed = false; item.Failure = null; } catch (Exception e) { _logger.LogError(e, $"Email sending error (item receiver: `{item.Receiver}`)"); item.Failed = true; item.Failure = e.Message; item.WaitFor = DateTimeOffset.UtcNow.Add(_configuration.RollUpStrategy.Delay); } } else { item.Failed = false; item.Failure = "Not sent (disabled)"; } }
private async Task <EmailMassSendingTaskContext> ProcessTaskAsync(EmailMassSendingTaskContext context, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var buffer = new byte[context.File.Length]; context.File.Position = 0; await context.File.ReadAsync(buffer, 0, buffer.Length, cancellationToken); var taskList = JsonConvert.DeserializeObject <EmailMassSendingTask>(Encoding.UTF8.GetString(buffer)); var taskItems = taskList.Items ?? new List <EmailMassSendingTaskItem>(); var allTaskItems = taskItems; taskItems = allTaskItems.Where(IsReadyToProcess).ToList(); if (!taskItems.Any()) { _logger.LogDebug($"No task items to process."); context.Success = true; return(context); } var partedTaskItems = new List <EmailMassSendingTaskItem> [_configuration.Threads]; var threadsCount = _configuration.Threads; for (var i = 0; i < threadsCount; i++) { partedTaskItems[i] = new List <EmailMassSendingTaskItem>(); } var q = new Queue <EmailMassSendingTaskItem>(taskItems); for (var i = 0; i < taskItems.Count; i++) { partedTaskItems[i % threadsCount].Add(q.Dequeue()); } Parallel.ForEach(partedTaskItems, new ParallelOptions { MaxDegreeOfParallelism = threadsCount }, (b) => { if (cancellationToken.IsCancellationRequested) { return; } ProcessTaskItemsAsync(context, b, cancellationToken).GetAwaiter().GetResult(); }); buffer = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(taskList, Formatting.Indented)); context.File.Position = 0; context.File.SetLength(buffer.Length); await context.File.WriteAsync(buffer, 0, buffer.Length, cancellationToken); await context.File.FlushAsync(cancellationToken); context.Success = allTaskItems.All(x => !IsNotObsolete(x) || (!x.Failed && x.Attempt != null)); context.Total = taskItems.Count; context.Sent = taskItems.Count(x => x.Attempt != null && !x.Failed); context.Failed = context.Total - context.Sent; return(context); }