Beispiel #1
0
        private WinPhone.Mail.Protocols.MailMessage GetMessage(string raw)
        {
            var msg = new WinPhone.Mail.Protocols.MailMessage();

            msg.Load(raw, Scope.HeadersAndBody);

            return(msg);
        }
Beispiel #2
0
 protected virtual void RaiseWarning(MailMessage mailMessage, string message)
 {
     var warning = Warning;
     if (warning != null)
     {
         warning(this, new WarningEventArgs { MailMessage = mailMessage, Message = message });
     }
 }
Beispiel #3
0
		public void Parse_Spam() {
			var dir = System.IO.Path.Combine(Environment.CurrentDirectory.Split(new[] { "AE.Net.Mail" }, StringSplitOptions.RemoveEmptyEntries)[0],
				"AE.Net.Mail\\Tests\\Spam");
			var files = System.IO.Directory.GetFiles(dir, "*.lorien", System.IO.SearchOption.AllDirectories);

			var mindate = new DateTime(1900, 1, 1).Ticks;
			var maxdate = DateTime.MaxValue.Ticks;
			var rxSubject = new Regex(@"^Subject\:\s+\S+");
			MailMessage msg = new MailMessage();
			for (var i = 0; i < files.Length; i++) {
				var file = files[i];
				var txt = System.IO.File.ReadAllText(file);
				using (var stream = System.IO.File.OpenRead(file))
					msg.Load(stream, Scope.HeadersAndBody, (int)stream.Length);

				if (msg.ContentTransferEncoding.IndexOf("quoted", StringComparison.OrdinalIgnoreCase) == -1) {
					continue;
				}

				if (string.IsNullOrEmpty(msg.Body)) {
					continue;
				}

				try {

					msg.Date.Ticks.ShouldBeInRange(mindate, maxdate);
                    Assert.True(!string.IsNullOrEmpty(msg.Subject) || !rxSubject.IsMatch(txt));
					//msg.From.ShouldBe();
					if (msg.To.Count > 0) msg.To.First().ShouldBe();
					if (msg.Cc.Count > 0) msg.Cc.First().ShouldBe();
					if (msg.Bcc.Count > 0) msg.Bcc.First().ShouldBe();

					(msg.Body ?? string.Empty).Trim().ShouldNotBeNullOrEmpty();


				} catch (Exception ex) {
					Console.WriteLine(ex);
					Console.WriteLine(txt);
					throw;
				}
			}
		}
Beispiel #4
0
        public void Attachment_SavesWithMessage()
        {
            var msg = new WinPhone.Mail.Protocols.MailMessage()
            {
                From  = new MailAddress("*****@*****.**"),
                Scope = Scope.HeadersAndBody,
            };
            var firstAttachmentContents = "This is a test.";
            var attachment = new Attachment()
            {
                Body = Convert.ToBase64String(Encoding.Default.GetBytes(firstAttachmentContents)),
                ContentTransferEncoding = "base64",
                Encoding = Encoding.ASCII,
                Scope    = Scope.HeadersAndBody,
            };

            attachment.Headers.Add("Content-Type", new HeaderValue(@"text/plain; filename=""Readme.txt"""));
            msg.Attachments.Add(attachment);

            var rnd = new Random();
            var secondAttachmentContents = new byte[rnd.Next(10, 1000)];

            rnd.NextBytes(secondAttachmentContents);
            attachment = new Attachment()
            {
                Body = Convert.ToBase64String(secondAttachmentContents),
                ContentTransferEncoding = "base64",
                Encoding = Encoding.ASCII,
                Scope    = Scope.HeadersAndBody,
            };
            attachment.Headers.Add("Content-Type", new HeaderValue(@"application/binary; filename=""Data.bin"""));
            msg.Attachments.Add(attachment);


            var reparsed = Reparse(msg);

            reparsed.Attachments.Count.ShouldBe(2);
            reparsed.Attachments.First().Filename.ShouldBe("Readme.txt");
            reparsed.Attachments.First().Body.ShouldBe(firstAttachmentContents);
            reparsed.Attachments.Last().Filename.ShouldBe("Data.bin");
            Convert.FromBase64String(reparsed.Attachments.Last().Body).ShouldBe(secondAttachmentContents);
        }
Beispiel #5
0
        public virtual async Task<MailMessage> GetMessageAsync(string uid, Scope scope = Scope.HeadersAndBody)
        {
            CheckConnectionStatus();
            var line = await SendCommandGetResponseAsync(string.Format(scope == Scope.Headers ? "TOP {0} 0" : "RETR {0}", uid));
            var size = rxOctets.Match(line).Groups[1].Value.ToInt();
            CheckResultOK(line);
            var msg = new MailMessage();
            msg.Load(_Stream, scope, size, '.');

            msg.Uid = uid;
            var last = await GetResponseAsync();
            if (string.IsNullOrEmpty(last))
                last = await GetResponseAsync();

            if (last != ".")
            {
                System.Diagnostics.Debugger.Break();
                RaiseWarning(msg, "Expected \".\" in stream, but received \"" + last + "\"");
            }

            return msg;
        }
Beispiel #6
0
        public async Task Download_Message()
        {
            var filename = System.IO.Path.GetTempFileName();

            try
            {
                using (var imap = await GetClientAsync <ImapClient>())
                    using (var file = new System.IO.FileStream(filename, System.IO.FileMode.Create))
                    {
                        await imap.DownloadMessageAsync(file, 0, false);
                    }

                using (var file = new System.IO.FileStream(filename, System.IO.FileMode.Open))
                {
                    var msg = new WinPhone.Mail.Protocols.MailMessage();
                    msg.Load(file, Scope.HeadersAndBody, maxLength: 0);
                    msg.Subject.ShouldNotBeNullOrEmpty();
                }
            }
            finally
            {
                File.Delete(filename);
            }
        }
Beispiel #7
0
        public void ParseBodyStructure()
        {
            MailMessage message = new MailMessage();
            Utilities.ParseBodyStructure(singleBodyStructure, message);
            Assert.Equal("text/plain", message.ContentType, StringComparer.OrdinalIgnoreCase);
            Assert.Equal("ISO-8859-1", message.Charset);
            Assert.Equal("7BIT", message.ContentTransferEncoding);

            message = new MailMessage();
            Utilities.ParseBodyStructure(multipartBodyStructure, message);
            Assert.Equal("multipart/alternative", message.ContentType, StringComparer.OrdinalIgnoreCase);
            Assert.Equal("047d7bea2f06ddf77e04ec9b2a60", message.Headers.GetBoundary());
            Assert.Equal(2, message.AlternateViews.Count);
            Assert.Equal(0, message.Attachments.Count);

            Attachment view = message.AlternateViews.First();
            Assert.Equal("text/plain", view.ContentType, StringComparer.OrdinalIgnoreCase);
            Assert.Equal("ISO-8859-1", view.Charset);
            Assert.Equal("7BIT", view.ContentTransferEncoding);

            view = message.AlternateViews.Skip(1).First();
            Assert.Equal("text/html", view.ContentType, StringComparer.OrdinalIgnoreCase);
            Assert.Equal("ISO-8859-1", view.Charset);
            Assert.Equal("7BIT", view.ContentTransferEncoding);
        }
Beispiel #8
0
 public Task SetStarAsync(MailMessage message, bool starred)
 {
     return SetStarAsync(new MailMessage[] { message }, starred);
 }
Beispiel #9
0
 public virtual async Task LazyLoadBodyPartAsync(MailMessage message, ObjectWHeaders part)
 {
     if (part.Scope < Scope.HeadersAndBody)
     {
         if (MailStorage.HasMessagePart(message.GetThreadId(), message.GetMessageId(), part.BodyId))
         {
             part.Body = await MailStorage.GetMessagePartAsync(message.GetThreadId(), message.GetMessageId(), part.BodyId);
         }
         else
         {
             await GmailImap.GetBodyPartAsync(message.Uid, part, async () =>
             {
                 if (ActiveLabel.Info.StoreMessages)
                 {
                     await MailStorage.StoreMessagePartAsync(message.GetThreadId(), message.GetMessageId(), part.BodyId, part.Body);
                 }
             }, CancellationToken.None);
         }
     }
 }
Beispiel #10
0
        public async Task OpenAttachmentAsync(MailMessage message, Attachment attachment)
        {
            // Lazy load
            if (attachment.Scope < Scope.HeadersAndBody)
            {
                // Check local storage
                if (MailStorage.HasMessagePart(message.GetThreadId(), message.GetMessageId(), attachment.BodyId))
                {
                    // TODO: Can we open the attachment directly from isolated storage?
                    attachment.Body = await MailStorage.GetMessagePartAsync(message.GetThreadId(), message.GetMessageId(), attachment.BodyId);
                }
                else
                {
                    // Download from the network
                    await GmailImap.GetBodyPartAsync(message.Uid, attachment, async () =>
                    {
                        if (ActiveLabel.Info.StoreMessages && ActiveLabel.Info.StoreAttachments)
                        {
                            await MailStorage.StoreMessagePartAsync(message.GetThreadId(), message.GetMessageId(), attachment.BodyId, attachment.Body);
                        }
                    }, CancellationToken.None);
                }
            }

            StorageFile file = await MailStorage.SaveAttachmentToTempAsync(attachment);
            // http://architects.dzone.com/articles/lap-around-windows-phone-8-sdk
            await Launcher.LaunchFileAsync(file);

            // TODO: Delete temp files on app close?
        }
Beispiel #11
0
 public async Task SendMessageAsync(MailMessage message)
 {
     // We don't send mail very often, so we don't need to keep the SmtpClient instance around.
     using (GmailSmtpClient client = new GmailSmtpClient(Info.Address, Info.Password))
     {
         await client.SendAsync(message);
     }
 }
Beispiel #12
0
 public Task StoreMessageFlagsAsync(MailMessage message)
 {
     return StoreMessageFlagsAsync(message.GetThreadId(), message.GetMessageId(), Utilities.FlagsToFlagString(message.Flags));
 }
Beispiel #13
0
 public Task StoreMessageHeadersAsync(MailMessage headers)
 {
     string messageDir = Path.Combine(AccountDir, _accountName, ConversationsDir, headers.GetThreadId(), headers.GetMessageId());
     if (!_storage.DirectoryExists(messageDir))
     {
         _storage.CreateDirectory(messageDir);
     }
     string headersFile = Path.Combine(messageDir, HeadersFile);
     using (Stream stream = _storage.CreateFile(headersFile))
     {
         // TODO: Async
         headers.Save(stream);
     }
     return Task.FromResult(0);
 }
Beispiel #14
0
        public virtual async Task<MailMessage[]> GetMessagesAsync(string start, string end, bool uid, Scope scope, bool setseen)
        {
            var x = new List<MailMessage>();

            await GetMessagesAsync(start, end, uid, scope, setseen,
                async (stream, size, imapHeaders) =>
                {
                    var mail = new MailMessage { Encoding = Encoding };
                    mail.Size = size;

                    if (imapHeaders["UID"] != null)
                        mail.Uid = imapHeaders["UID"];

                    if (imapHeaders["Flags"] != null)
                        mail.SetFlags(imapHeaders["Flags"]);

                    await _Stream.EnsureBufferAsync(mail.Size);
                    mail.Load(_Stream, scope, mail.Size);

                    foreach (var key in imapHeaders.Keys.Except(new[] { "UID", "Flags", "BODY[]", "BODY[HEADER]" }, StringComparer.OrdinalIgnoreCase))
                        mail.Headers.Add(key, new HeaderValue(imapHeaders[key]));

                    x.Add(mail);

                    return mail;
                }
            );

            return x.ToArray();
        }
Beispiel #15
0
        public virtual async Task AppendMailAsync(MailMessage email, string mailbox = null)
        {
            await IdlePauseAsync();

            mailbox = ModifiedUtf7Encoding.Encode(mailbox);
            string flags = String.Empty;
            var body = new StringBuilder();
            using (var txt = new System.IO.StringWriter(body))
                email.Save(txt);

            string size = body.Length.ToString();
            if (email.RawFlags.Length > 0)
            {
                flags = " (" + string.Join(" ", email.Flags) + ")";
            }

            if (mailbox == null)
                await CheckMailboxSelectedAsync();
            mailbox = mailbox ?? _SelectedMailbox;

            string command = GetTag() + "APPEND " + (mailbox ?? _SelectedMailbox).QuoteString() + flags + " {" + size + "}";
            string response = await SendCommandGetResponseAsync(command);
            if (response.StartsWith("+"))
            {
                response = await SendCommandGetResponseAsync(body.ToString());
            }
            await IdleResumeAsync();
        }
Beispiel #16
0
        private WinPhone.Mail.Protocols.MailMessage GetMessage(string raw)
        {
            var msg = new WinPhone.Mail.Protocols.MailMessage();
            msg.Load(raw, Scope.HeadersAndBody);

            return msg;
        }
Beispiel #17
0
        private MailMessage Reparse(MailMessage msg)
        {
            var sb = new StringBuilder();
            using (var w = new StringWriter(sb))
            {
                msg.Save(w);
            }
            // System.Diagnostics.Debug.WriteLine(sb.ToString());

            var parsedMessage = GetMessage(sb.ToString());
            return parsedMessage;
        }
Beispiel #18
0
        public void Attachment_SavesWithMessage()
        {
            var msg = new WinPhone.Mail.Protocols.MailMessage()
            {
                From = new MailAddress("*****@*****.**"),
                Scope = Scope.HeadersAndBody,
            };
            var firstAttachmentContents = "This is a test.";
            var attachment = new Attachment()
            {
                Body = Convert.ToBase64String(Encoding.Default.GetBytes(firstAttachmentContents)),
                ContentTransferEncoding = "base64",
                Encoding = Encoding.ASCII,
                Scope = Scope.HeadersAndBody,
            };
            attachment.Headers.Add("Content-Type", new HeaderValue(@"text/plain; filename=""Readme.txt"""));
            msg.Attachments.Add(attachment);

            var rnd = new Random();
            var secondAttachmentContents = new byte[rnd.Next(10, 1000)];
            rnd.NextBytes(secondAttachmentContents);
            attachment = new Attachment()
            {
                Body = Convert.ToBase64String(secondAttachmentContents),
                ContentTransferEncoding = "base64",
                Encoding = Encoding.ASCII,
                Scope = Scope.HeadersAndBody,
            };
            attachment.Headers.Add("Content-Type", new HeaderValue(@"application/binary; filename=""Data.bin"""));
            msg.Attachments.Add(attachment);


            var reparsed = Reparse(msg);
            reparsed.Attachments.Count.ShouldBe(2);
            reparsed.Attachments.First().Filename.ShouldBe("Readme.txt");
            reparsed.Attachments.First().Body.ShouldBe(firstAttachmentContents);
            reparsed.Attachments.Last().Filename.ShouldBe("Data.bin");
            Convert.FromBase64String(reparsed.Attachments.Last().Body).ShouldBe(secondAttachmentContents);
        }
Beispiel #19
0
 public virtual Task DeleteMessageAsync(MailMessage msg)
 {
     return DeleteMessageAsync(msg.Uid);
 }
Beispiel #20
0
        public void ParseNestedMultipartBodyStructure()
        {
            MailMessage message = new MailMessage();
            Utilities.ParseBodyStructure(nestedMultipart, message);
            Assert.Equal("multipart/mixed", message.ContentType, StringComparer.OrdinalIgnoreCase);
            Assert.Equal("047d7ba97f3abafb0004e9ab4939", message.Headers.GetBoundary());
            Assert.Equal(2, message.AlternateViews.Count);
            Assert.Equal(3, message.Attachments.Count);

            Attachment view = message.AlternateViews.First();
            Assert.Equal("text/plain", view.ContentType, StringComparer.OrdinalIgnoreCase);
            Assert.Equal("ISO-8859-1", view.Charset);
            Assert.Equal("7BIT", view.ContentTransferEncoding);
            Assert.Equal("1.1", view.BodyId);

            view = message.AlternateViews.Skip(1).First();
            Assert.Equal("text/html", view.ContentType, StringComparer.OrdinalIgnoreCase);
            Assert.Equal("ISO-8859-1", view.Charset);
            Assert.Equal("7BIT", view.ContentTransferEncoding);
            Assert.Equal("1.2", view.BodyId);

            Attachment attachment = message.Attachments.First();
            Assert.Equal("image/png", attachment.ContentType, StringComparer.OrdinalIgnoreCase);
            Assert.Equal("Screenshot_2013-10-26-14-07-32.png", attachment.Filename);
            Assert.Equal("BASE64", attachment.ContentTransferEncoding);
            Assert.Equal("2", attachment.BodyId);

            attachment = message.Attachments.Skip(1).First();
            Assert.Equal("image/png", attachment.ContentType, StringComparer.OrdinalIgnoreCase);
            Assert.Equal("Screenshot_2013-10-26-14-07-46.png", attachment.Filename);
            Assert.Equal("BASE64", attachment.ContentTransferEncoding);
            Assert.Equal("3", attachment.BodyId);

            attachment = message.Attachments.Skip(2).First();
            Assert.Equal("image/png", attachment.ContentType, StringComparer.OrdinalIgnoreCase);
            Assert.Equal("Screenshot_2013-10-26-14-05-49.png", attachment.Filename);
            Assert.Equal("BASE64", attachment.ContentTransferEncoding);
            Assert.Equal("4", attachment.BodyId);
        }
Beispiel #21
0
 // Break the message up into parts: Flags, labels, headers/structure, and body parts
 public async Task StoreMessageAsync(MailMessage message)
 {
     await StoreMessageFlagsAsync(message.GetThreadId(), message.GetMessageId(), Utilities.FlagsToFlagString(message.Flags));
     await StoreMessageLabelsAsync(message.GetThreadId(), message.GetMessageId(), message.GetLabelsHeader());
     await StoreMessageHeadersAsync(message);
     if (message.Scope >= Scope.HeadersAndBodySnyppit)
     {
         // TODO: Verify BodyId is set.
         // Body parts
         if (!message.AlternateViews.Any() && !message.Attachments.Any())
         {
             // Simple body
             await StoreMessagePartAsync(message.GetThreadId(), message.GetMessageId(), message.BodyId, message.Body);
         }
         else
         {
             // Multipart body
             foreach (Attachment view in message.AlternateViews)
             {
                 await StoreMessagePartAsync(message.GetThreadId(), message.GetMessageId(), view.BodyId, view.Body);
             }
             foreach (Attachment attachment in message.Attachments)
             {
                 await StoreMessagePartAsync(message.GetThreadId(), message.GetMessageId(), attachment.BodyId, attachment.Body);
             }
         }
     }
 }
Beispiel #22
0
        public void SaveAndLoadHeadersOnly()
        {
            MailMessage message1 = new MailMessage();
            message1.Scope = Scope.HeadersAndMime;

            message1.Sender = new MailAddress("*****@*****.**");
            message1.From = new MailAddress("*****@*****.**");
            message1.To.Add(new MailAddress("*****@*****.**"));
            message1.Cc.Add(new MailAddress("*****@*****.**"));
            message1.Bcc.Add(new MailAddress("*****@*****.**"));
            message1.Subject = "Subject line";

            message1.ContentType = "text/plain; charset=utf-8";

            MemoryStream buffer = new MemoryStream();
            TextWriter writer = new StreamWriter(buffer);
            message1.Save(writer);
            writer.Flush();
            buffer.Seek(0, SeekOrigin.Begin);

            MailMessage message2 = new MailMessage();
            message2.Load(buffer, Scope.Headers, 0);

            Assert.Equal(message1.Sender.ToString(), message2.Sender.ToString());
            Assert.Equal(message1.From.ToString(), message2.From.ToString());
            Assert.Equal(message1.To.First().ToString(), message2.To.First().ToString());
            Assert.Equal(message1.Cc.First().ToString(), message2.Cc.First().ToString());
            Assert.Equal(message1.Bcc.First().ToString(), message2.Bcc.First().ToString());

            Assert.Equal(message1.Subject, message2.Subject);
            Assert.Equal(message1.ContentType, message2.ContentType);
            Assert.Equal(message1.Body, message2.Body);
            Assert.Equal(message1.AlternateViews.Count, message1.AlternateViews.Count);
            Assert.Equal(message1.Attachments.Count, message1.Attachments.Count);
        }
Beispiel #23
0
 public Task StoreMessageLabelsAsync(MailMessage message)
 {
     return StoreMessageLabelsAsync(message.GetThreadId(), message.GetMessageId(), message.GetLabelsHeader());
 }
Beispiel #24
0
        public void SaveAndLoadHeadersOnlyMultipart()
        {
            MailMessage message1 = new MailMessage();
            message1.Scope = Scope.HeadersAndMime;

            message1.Sender = new MailAddress("*****@*****.**");
            message1.From = new MailAddress("*****@*****.**");
            message1.To.Add(new MailAddress("*****@*****.**"));
            message1.Cc.Add(new MailAddress("*****@*****.**"));
            message1.Bcc.Add(new MailAddress("*****@*****.**"));
            message1.Subject = "Subject line";

            message1.ContentType = "multipart/mixed; boundary=abcdefg";
            message1.AlternateViews.Add(new Attachment()
            {
               ContentType = "text/plain; charset=utf-8",
               ContentTransferEncoding = "7BIT",
            });
            message1.Attachments.Add(new Attachment()
            {
                ContentType = "text/plain; charset=utf-8",
                ContentTransferEncoding = "7BIT",
                IsAttachment = true,
            });

            MemoryStream buffer = new MemoryStream();
            TextWriter writer = new StreamWriter(buffer);
            message1.Save(writer);
            writer.Flush();
            buffer.Seek(0, SeekOrigin.Begin);

            MailMessage message2 = new MailMessage();
            message2.Load(buffer, Scope.HeadersAndMime, 0);

            Assert.Equal(message1.Sender.ToString(), message2.Sender.ToString());
            Assert.Equal(message1.From.ToString(), message2.From.ToString());
            Assert.Equal(message1.To.First().ToString(), message2.To.First().ToString());
            Assert.Equal(message1.Cc.First().ToString(), message2.Cc.First().ToString());
            Assert.Equal(message1.Bcc.First().ToString(), message2.Bcc.First().ToString());

            Assert.Equal(message1.Subject, message2.Subject);
            Assert.Equal(message1.ContentType, message2.ContentType);
            Assert.Equal(message1.Body, message2.Body);
            Assert.Equal(message1.AlternateViews.Count, message1.AlternateViews.Count);
            Assert.Equal(message1.Attachments.Count, message1.Attachments.Count);

            Assert.Equal(message1.AlternateViews.First().ContentType, message2.AlternateViews.First().ContentType);
            Assert.Equal(message1.AlternateViews.First().ContentTransferEncoding, message2.AlternateViews.First().ContentTransferEncoding);
            Assert.Equal(message1.AlternateViews.First().IsAttachment, message2.AlternateViews.First().IsAttachment);

            Assert.Equal(message1.Attachments.First().ContentType, message2.Attachments.First().ContentType);
            Assert.Equal(message1.Attachments.First().ContentTransferEncoding, message2.Attachments.First().ContentTransferEncoding);
            Assert.Equal(message1.Attachments.First().IsAttachment, message2.Attachments.First().IsAttachment);
        }
Beispiel #25
0
 public Task<MailMessage> GetMessageHeadersAsync(string conversationId, string messageId)
 {
     string messageDir = Path.Combine(AccountDir, _accountName, ConversationsDir, conversationId, messageId);
     string headersFile = Path.Combine(messageDir, HeadersFile);
     if (!_storage.DirectoryExists(messageDir) || !_storage.FileExists(headersFile))
     {
         return null;
     }
     Stream stream = _storage.OpenFile(headersFile, FileMode.Open, FileAccess.Read, FileShare.Read);
     using (stream)
     {
         // TODO: Async
         MailMessage message = new MailMessage();
         message.Load(stream, Scope.HeadersAndMime, 0);
         return Task.FromResult(message);
     }
 }
        private async void SetReadStatus(bool readStatus)
        {
            ProgressIndicator.IsIndeterminate = true;
            try
            {
                IEnumerable<MailMessage> messages = new MailMessage[0];
                foreach (ConversationThread conversation in MailList.SelectedItems)
                {
                    messages = messages.Concat(conversation.Messages);
                }
                messages = messages.Where(message => message.Seen != readStatus);
                if (messages.Any())
                {
                    Account account = App.AccountManager.GetCurrentAccount();
                    await account.SetReadStatusAsync(messages.ToList(), read: readStatus);

                    // Force Refresh
                    var temp = MailList.ItemsSource;
                    MailList.ItemsSource = null;
                    MailList.ItemsSource = temp;
                }
            }
            finally
            {
                MailList.IsSelectionEnabled = false;
                ProgressIndicator.IsIndeterminate = false;
            }
        }
        private async void Send(object sender, EventArgs e)
        {
            Account account = App.AccountManager.GetCurrentAccount();
            if (account == null)
            {
                return;
            }

            // TODO: validate fields

            MailMessage message = new MailMessage();
            message.Date = DateTime.Now;
            message.From = new MailAddress(account.Info.Address, account.Info.DisplayName);
            MailAddressParser.ParseAddressField(ToField.Text.Trim()).ForEach(message.To.Add);
            message.Subject = SubjectField.Text.Trim();
            message.ContentType = "text/plain; charset=utf-8";
            message.ContentTransferEncoding = "quoted-printable";
            message.Body = BodyField.Text;

            foreach (var pair in _additionalHeaders)
            {
                message.Headers.Add(pair.Key, new HeaderValue(pair.Value));
            }

            // TODO: Short term: Progress bar
            ProgressIndicator.IsIndeterminate = true;
            try
            {
                // TODO: Long term: Save to drafts and memory, then send in the background. Retry if no connectivity.
                await account.SendMessageAsync(message);
            }
            finally
            {
                ProgressIndicator.IsIndeterminate = false;
            }

            NavigationService.GoBack();
        }
        // TODO: Special case Spam folder? Perminately delete.
        // TODO: Remove from current label, storage.
        private async void SpamClick(object sender, EventArgs e)
        {
            ProgressIndicator.IsIndeterminate = true;
            try
            {
                IEnumerable<MailMessage> messages = new MailMessage[0];
                foreach (ConversationThread conversation in MailList.SelectedItems)
                {
                    messages = messages.Concat(conversation.Messages);
                }
                if (messages.Any())
                {
                    Account account = App.AccountManager.GetCurrentAccount();
                    await account.TrashAsync(messages.ToList(), isSpam: true);

                    // Force Refresh
                    GetConversations();
                }
            }
            finally
            {
                MailList.IsSelectionEnabled = false;
                ProgressIndicator.IsIndeterminate = false;
            }
        }