public DeliverAsync (
|
||
message | ||
recipients | List |
|
리턴 | Task
|
public async Task<List<DeliveryResult>> DeliverAsync(Message message, List<Recipient> recipients)
{
if (message == null)
throw new ArgumentNullException(nameof(message));
if (message.Recipients == null)
throw new ArgumentNullException(nameof(message.Recipients));
var result = new List<DeliveryResult>();
foreach (var localRecipient in recipients)
{
_log.LogInfo(new LogEvent()
{
EventType = LogEventType.Application,
LogLevel = LogLevel.Info,
Message = $"Delivering message from {message.From} to {localRecipient.Address}",
Protocol = "SMTPD",
});
var localAccount = await _accountRepository.GetByIdAsync(localRecipient.AccountId);
// TODO: Check quotas
var inbox = await _folderRepository.GetInbox(localAccount.Id);
var accountLevelMessage = await _messageRepository.CreateAccountLevelMessageAsync(message, localAccount, inbox);
// TODO: Execute rules
// TODO: Perform forwarding
// TODO: Add Trace headers.
// TODO: Etc
accountLevelMessage.State = MessageState.Delivered;
await _messageRepository.InsertAsync(accountLevelMessage);
// Delete the recipient right away, so that if there is a crash we don't end up sending to this recipient again.
await _messageRepository.DeleteRecipientAsync(localRecipient);
result.Add(new DeliveryResult(localRecipient.Address, ReplyCodeSeverity.Positive, "Message delivered."));
}
return result;
}
}
private async Task DeliverMessageAsync(Message message) { var accountRepository = _container.GetInstance <IAccountRepository>(); var messageRepository = _container.GetInstance <IMessageRepository>(); var folderRepository = _container.GetInstance <IFolderRepository>(); var dnsClient = _container.GetInstance <IDnsClient>(); message.NumberOfDeliveryAttempts++; bool isLastAttempt = message.NumberOfDeliveryAttempts >= 3; var deliveryResults = new List <DeliveryResult>(); try { var remainingRecipients = new List <Recipient>(message.Recipients); var localDelivery = new LocalDelivery(accountRepository, messageRepository, folderRepository, _log); deliveryResults.AddRange(await localDelivery.DeliverAsync(message, remainingRecipients.Where(recipient => recipient.AccountId != 0).ToList())); var externalDelivery = new ExternalDelivery(messageRepository, dnsClient, _log); deliveryResults.AddRange(await externalDelivery.DeliverAsync(message, remainingRecipients.Where(recipient => recipient.AccountId == 0).ToList())); var failedRecipients = deliveryResults.Where(result => result.ReplyCodeSeverity == ReplyCodeSeverity.PermanentNegative || (isLastAttempt && result.ReplyCodeSeverity == ReplyCodeSeverity.TransientNegative)); await SubmitBounceMessageAsync(message, failedRecipients); var deliveryCompleted = deliveryResults.Any(result => result.ReplyCodeSeverity == ReplyCodeSeverity.TransientNegative); if (isLastAttempt || !deliveryCompleted) { await messageRepository.DeleteAsync(message); } } catch (Exception ex) { var logEvent = new LogEvent() { EventType = LogEventType.Application, LogLevel = LogLevel.Error, Protocol = "SMTPD", }; if (isLastAttempt) { logEvent.Message = "Failed delivering message due to an error. Giving up."; } else { logEvent.Message = "Failed delivering message due to an error. Will retry later."; } _log.LogException(logEvent, ex); if (isLastAttempt) { await messageRepository.DeleteAsync(message); } else { await messageRepository.UpdateAsync(message); } } }