Example #1
0
        public async Task <bool> TrySendSingleMailAsync(
            IMailReference mail,
            StreamWriter writer,
            StreamReader reader,
            CancellationToken token)
        {
            _log.Information($"Sending mail {mail.Id}");
            IMailReadReference readMail = await _queue.OpenReadAsync(mail, token);

            _log.Information($"Sender: {readMail.Sender}, Recipients: {string.Join(",", readMail.Recipients)}");
            SmtpResponse response = await ExecuteRemoteCommandAsync(writer, reader, $"MAIL FROM:<{readMail.Sender}>");

            if (response.Code != SmtpReplyCode.Okay)
            {
                _log.Warning("Failed MAIL FROM, aborting");
                return(false);
            }

            foreach (string recipient in readMail.Recipients)
            {
                response = await ExecuteRemoteCommandAsync(writer, reader, $"RCPT TO:<{recipient}>");

                if (response.Code != SmtpReplyCode.Okay)
                {
                    _log.Warning("Failed RCPT TO, aborting");
                    return(false);
                }
            }

            response = await ExecuteRemoteCommandAsync(writer, reader, "DATA");

            if (response.Code != SmtpReplyCode.StartMail)
            {
                _log.Warning("Failed DATA, aborting");
                return(false);
            }

            using (var mailReader = new StreamReader(readMail.BodyStream))
            {
                string line = null;
                while (await mailReader.TryReadLineAsync(l => line = l, token))
                {
                    await writer.WriteLineAsync(line);
                }
            }

            await writer.WriteLineAsync(".");

            response = await ReadResponseAsync(reader);

            if (response.Code != SmtpReplyCode.Okay)
            {
                _log.Warning("Failed RCPT TO, aborting");
                return(false);
            }

            await _queue.DeleteAsync(mail);

            return(true);
        }
Example #2
0
        public Task DeleteAsync(IMailReference reference)
        {
            var mockReference = (MockMailReference)reference;

            References.Remove(mockReference);
            DeletedReferences.Add(mockReference);
            return(Task.CompletedTask);
        }
Example #3
0
        public Task DeleteAsync(IMailReference reference)
        {
            var mailReference = reference as IReference;

            if (mailReference != null && File.Exists(mailReference.Path))
            {
                File.Delete(mailReference.Path);
            }
            return(Task.FromResult((object)null));
        }
Example #4
0
        public SmtpFailureData ShouldAttemptRedelivery(IMailReference mail)
        {
            SmtpFailureData failure = _failures.GetFailure(mail.Id, true);

            if (failure.Retries + 1 >= s_retryDelays.Length)
            {
                return(null);
            }

            return(failure);
        }
Example #5
0
        public virtual Task DeleteAsync(IMailReference reference)
        {
            if (reference is IReference mailReference)
            {
                if (File.Exists(mailReference.Path))
                {
                    File.Delete(mailReference.Path);
                }
            }

            return(Task.CompletedTask);
        }
Example #6
0
 /// <summary>
 /// use this method for template-driven email messages
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="recipients"></param>
 /// <param name="mailReference"></param>
 public void BuildEmailMessage(string sender, IList <string> recipients, IMailReference mailReference)
 {
     try
     {
         IMail email = _composer.Compose(sender, recipients, mailReference);
         _client.SendEmail(email);
     }
     catch (Exception)
     {
         throw;
     }
 }
        public IMail Compose(string sender, IList <string> recipients, IMailReference mailReference)
        {
            // build email message
            // get email template
            string emailTemplate = _templateFactory.GetEmailTemplateMessage(mailReference.MessageType);
            // replace markers from email template
            Dictionary <string, string> dictMarkers = mailReference.MapObjectDictionary();

            foreach (var item in dictMarkers)
            {
                emailTemplate = emailTemplate.Replace("##" + item.Key + "##", item.Value);
            }

            return(new Mail(sender, recipients, mailReference.EmailSubject, emailTemplate, mailReference.ContentType));
        }
        public override async Task DeleteAsync(IMailReference reference)
        {
            await base.DeleteAsync(reference);

            try
            {
                // var mailReference = (Reference) reference;
                // root/in/domain.name/cur/mail-id-path.mbx
                // we want to remove the domain.name directory if this is the last mail going into it
                // Directory.Delete(Path.GetDirectoryName(Path.GetDirectoryName(mailReference.Path)));
            }
            catch (Exception)
            {
                // Don't care, we were just cleaning up after ourselves, after all
            }
        }
Example #9
0
        public async Task <IMailReadReference> OpenReadAsync(IMailReference reference)
        {
            var mailReference = reference as IReference;

            if (mailReference == null)
            {
                throw new ArgumentNullException(nameof(reference));
            }

            using (var stream = Sharable.Create(File.OpenRead(mailReference.Path)))
            {
                string        sender;
                List <string> recipients = new List <string>();
                using (var reader = new StreamReader(stream.Peek(), Encoding.UTF8, false, 1024, true))
                {
                    var fromLine = await reader.ReadLineAsync();

                    if (!fromLine.StartsWith("FROM:"))
                    {
                        throw new FormatException("Invalid mail file format, expected FROM line");
                    }

                    sender = fromLine.Substring(5);

                    while (true)
                    {
                        var line = await reader.ReadLineAsync();

                        if (line.StartsWith("---"))
                        {
                            break;
                        }

                        if (line.StartsWith("TO:"))
                        {
                            recipients.Add(line.Substring(3));
                            continue;
                        }

                        throw new FormatException("Invalid mail file format, expected TO: line or Begin Message");
                    }
                }

                return(new ReadReference(sender, recipients, mailReference.Path, stream.TakeValue()));
            }
        }
Example #10
0
        public bool IsReadyToSend(IMailReference mail)
        {
            SmtpFailureData failure = _failures.GetFailure(mail.Id, false);

            if (failure == null)
            {
                return(true);
            }

            TimeSpan currentLag = DateTimeOffset.UtcNow - failure.FirstFailure;

            if (currentLag < CalculateNextRetryInterval(failure.Retries))
            {
                return(false);
            }

            return(true);
        }
Example #11
0
 public Task <IMailReadReference> OpenReadAsync(IMailReference reference, CancellationToken token)
 {
     return(Task.FromResult((IMailReadReference)reference));
 }
Example #12
0
        public async Task <IMailReadReference> OpenReadAsync(IMailReference reference, CancellationToken token)
        {
            var mailReference = reference as Reference;

            if (mailReference == null)
            {
                throw new ArgumentNullException(nameof(reference));
            }

            using (Sharable <FileStream> stream = Sharable.Create(File.OpenRead(mailReference.Path)))
            {
                string     sender;
                var        recipients = new List <string>();
                FileStream streamImpl = stream.Peek();
                // 23 ASCII characters, up to 1 GB in size, should be sufficient
                // Header-Legnth:000000000
                string headerSizeHeader = Encoding.ASCII.GetString(await streamImpl.ReadExactlyAsync(23, token));

                if (!headerSizeHeader.StartsWith(HeaderLengthHeader))
                {
                    throw new FormatException($"Invalid mail file format, expected {HeaderLengthHeader} line");
                }

                if (!int.TryParse(headerSizeHeader.Substring(HeaderLengthHeader.Length), out int headerSize) || headerSize <= 0)
                {
                    throw new FormatException($"Invalid mail file format, {HeaderLengthHeader} is not a valid number");
                }

                using (var reader = new StreamReader(new StreamSpan(streamImpl, 0, headerSize), Encoding.UTF8, false, 1, true))
                {
                    // This should be the "new line" at the end of the Header-Length we've already consumed
                    // so all that is left is the rest of the line (which is empty).
                    // If it's not, then we didn't read what we thought we read, bail
                    string blankLine = await reader.ReadLineAsync();

                    if (!string.IsNullOrEmpty(blankLine))
                    {
                        throw new FormatException($"Invalid mail file format, {HeaderLengthHeader} is improperly formatted");
                    }

                    string fromLine = await reader.ReadLineAsync();

                    if (!fromLine.StartsWith("FROM:"))
                    {
                        throw new FormatException("Invalid mail file format, expected FROM line");
                    }

                    sender = fromLine.Substring(5);

                    string line = null;
                    while (await reader.TryReadLineAsync(l => line = l, token))
                    {
                        if (line.StartsWith("TO:"))
                        {
                            recipients.Add(line.Substring(3));
                            continue;
                        }

                        throw new FormatException("Invalid mail file format, expected TO: line or Begin Message");
                    }
                }

                return(new ReadReference(
                           mailReference.Id,
                           sender,
                           recipients,
                           mailReference.Path,
                           new StreamSpan(stream.TakeValue()),
                           this));
            }
        }
Example #13
0
 private Task HandleRejectedMailAsync(IMailReference mail)
 {
     _log.Warning($"Max reties attempted for mail {mail.Id}, deleting");
     return(Task.CompletedTask);
 }