Пример #1
0
        /// <summary>
        /// Send mail and awaits until all messages are sent
        /// </summary>
        /// <param name="writer">Writer</param>
        /// <param name="result">Mail result to send</param>
        /// <param name="endPoint">End point</param>
        /// <param name="dispose">Whether to dispose result when done</param>
        /// <param name="prepMessage">Allow changing mime message right before it is sent</param>
        /// <returns>Task</returns>
        private async Task SendMail(StreamWriter writer, MailFromResult result, IPEndPoint endPoint, bool dispose, Action <MimeMessage> prepMessage)
        {
            try
            {
                // send all emails in one shot for each domain in order to batch
                DateTime    start = DateTime.UtcNow;
                int         count = 0;
                List <Task> tasks = new List <Task>();
                foreach (var group in result.ToAddresses)
                {
                    tasks.Add(SendMailInternal(writer, result.BackingFile, result.From, group.Key, group.Value, endPoint, null));
                    count++;
                }
                await Task.WhenAll(tasks);

                MailDemonLog.Info("Sent {0} batches of messages in {1:0.00} seconds", count, (DateTime.UtcNow - start).TotalSeconds);
            }
            catch (Exception ex)
            {
                MailDemonLog.Error(ex);
            }
            finally
            {
                if (dispose)
                {
                    result.Dispose();
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Send mail and kicks off the send in a new task
        /// </summary>
        /// <param name="foundUser">Found user</param>
        /// <param name="reader">Reader</param>
        /// <param name="writer">Writer</param>
        /// <param name="line">Line</param>
        /// <param name="endPoint">End point</param>
        /// <param name="prepMessage">Allow changing mime message right before it is sent</param>
        /// <returns>Task</returns>
        private async Task SendMail(MailDemonUser foundUser, Stream reader, StreamWriter writer, string line, IPEndPoint endPoint, Action <MimeMessage> prepMessage)
        {
            MailFromResult result = await ParseMailFrom(foundUser, reader, writer, line, endPoint);

            SendMail(writer, result, endPoint, true, prepMessage).GetAwaiter();
            await writer.WriteLineAsync($"250 2.1.0 OK");

            await writer.FlushAsync();
        }
Пример #3
0
        private async Task <bool> ReceiveMail(Stream reader, StreamWriter writer, string line, IPEndPoint endPoint)
        {
            IPHostEntry entry = await Dns.GetHostEntryAsync(endPoint.Address);

            MailFromResult result = await ParseMailFrom(null, reader, writer, line, endPoint);

            if (result is null)
            {
                return(false);
            }
            try
            {
                string      subject;
                MimeMessage msg;
                using (Stream stream = File.OpenRead(result.BackingFile))
                {
                    msg = await MimeMessage.LoadAsync(stream, true, cancelToken);

                    subject = msg.Subject;
                }
                subject = (subject ?? string.Empty).Trim();
                if (subject.Equals("unsubscribe", StringComparison.OrdinalIgnoreCase))
                {
                    UnsubscribeHandler?.Invoke(result.From.Address, subject, msg.HtmlBody);
                    return(true);
                }

                // mail demon doesn't have an inbox yet, only forwarding, so see if any of the to addresses can be forwarded
                foreach (var kv in result.ToAddresses)
                {
                    foreach (MailboxAddress address in kv.Value)
                    {
                        MailDemonUser user = users.FirstOrDefault(u => u.MailAddress.Address.Equals(address.Address, StringComparison.OrdinalIgnoreCase));

                        // if no user or the forward address points to a user, fail
                        if (user == null || users.FirstOrDefault(u => u.MailAddress.Address.Equals(user.ForwardAddress.Address, StringComparison.Ordinal)) != null)
                        {
                            await writer.WriteLineAsync($"500 invalid command - user not found");

                            await writer.FlushAsync();
                        }

                        // setup forward headers
                        MailboxAddress forwardToAddress = (user.ForwardAddress ?? globalForwardAddress);
                        if (forwardToAddress == null)
                        {
                            await writer.WriteLineAsync($"500 invalid command - user not found 2");

                            await writer.FlushAsync();
                        }
                        else
                        {
                            string forwardDomain = forwardToAddress.Address.Substring(forwardToAddress.Address.IndexOf('@') + 1);

                            // create new object to forward on
                            MailFromResult newResult = new MailFromResult
                            {
                                BackingFile = result.BackingFile,
                                From        = user.MailAddress,
                                ToAddresses = new Dictionary <string, IEnumerable <MailboxAddress> > {
                                    { forwardDomain, new List <MailboxAddress> {
                                          forwardToAddress
                                      } }
                                }
                            };

                            // forward the message on and clear the forward headers
                            MailDemonLog.Info("Forwarding message, from: {0}, to: {1}, forward: {2}", result.From, address, forwardToAddress);
                            result.BackingFile = null; // we took ownership of the file

                            // send in background
                            SendMail(newResult, true, prepMsg =>
                            {
                                prepMsg.Subject = $"FW from {result.From}: {prepMsg.Subject}";
                                prepMsg.Cc.Clear();
                                prepMsg.Bcc.Clear();
                            }, false).ConfigureAwait(false).GetAwaiter();
                            return(true); // only forward to the first valid address
                        }
                    }
                }
            }
            finally
            {
                result.Dispose();
            }
            return(true);
        }