public void LoadEmbeddedAttachments(MimeMessage message) { var embeddedAttachments = new List <MimeEntity>(); var iter = new MimeIterator(message); while (iter.MoveNext()) { var part = iter.Current as MimePart; if (part == null) { continue; } if (string.IsNullOrEmpty(part.ContentId) && part.ContentLocation == null) { continue; } if (part is TextPart) { continue; } embeddedAttachments.Add(part); } if (embeddedAttachments.Any()) { LoadAttachments(embeddedAttachments); } }
public void TestPathSpecifiers() { var expectedTypes = new Type[] { typeof(Multipart), typeof(TextPart), typeof(MimePart), typeof(MessagePart), typeof(Multipart), typeof(TextPart), typeof(MimePart), typeof(Multipart), typeof(MimePart), typeof(MessagePart), typeof(Multipart), typeof(TextPart), typeof(MultipartAlternative), typeof(TextPart), typeof(TextPart) }; var expectedPathSpecifiers = new string[] { "0", "1", "2", "3", "3.0", "3.1", "3.2", "4", "4.1", "4.2", "4.2.0", "4.2.1", "4.2.2", "4.2.2.1", "4.2.2.2" }; var expectedDepths = new int[] { 0, 1, 1, 1, 2, 3, 3, 1, 2, 2, 3, 4, 4, 5, 5 }; var expectedParents = new List <MimeEntity> { null }; var message = CreateImapExampleMessage(expectedParents); var iter = new MimeIterator(message); int i = 0; Assert.IsTrue(iter.MoveNext(), "Initialize"); do { var current = iter.Current; var parent = iter.Parent; Assert.AreEqual(expectedDepths[i], iter.Depth, "Depth #{0}", i); Assert.AreEqual(expectedParents[i], parent, "Parent #{0}", i); Assert.IsInstanceOf(expectedTypes[i], current, "Type #{0}", i); Assert.AreEqual(expectedPathSpecifiers[i], iter.PathSpecifier, "PathSpecifier #{0}", i); i++; } while (iter.MoveNext()); Assert.AreEqual(expectedTypes.Length, i); iter.Reset(); i = 0; Assert.IsTrue(iter.MoveNext(), "Reset"); do { var current = iter.Current; var parent = iter.Parent; Assert.AreEqual(expectedDepths[i], iter.Depth, "Reset Depth #{0}", i); Assert.AreEqual(expectedParents[i], parent, "Reset Parent #{0}", i); Assert.IsInstanceOf(expectedTypes[i], current, "Reset Type #{0}", i); Assert.AreEqual(expectedPathSpecifiers[i], iter.PathSpecifier, "Reset PathSpecifier #{0}", i); i++; } while (iter.MoveNext()); }
static void DumpMimeTree(StringBuilder builder, MimeMessage message) { using (var iter = new MimeIterator(message)) { while (iter.MoveNext()) { var ctype = iter.Current.ContentType; if (iter.Depth > 0) { builder.Append(new string (' ', iter.Depth * 3)); } builder.AppendFormat("Content-Type: {0}/{1}", ctype.MediaType, ctype.MediaSubtype).Append('\n'); } } }
static void insert_attachments(int post_id, int issue_id, MimeMessage message) { using (var iter = new MimeIterator(message)) { // collect our list of attachments and their parent multiparts while (iter.MoveNext()) { var multipart = iter.Parent as Multipart; var part = iter.Current as MimePart; if (part is not null) { if (part.FileName is not null) { bd_issue.insert_post_attachment_from_email_attachment(post_id, issue_id, part); } } } } }
private static IList <MimePart> GetMessageAttachments(MimeMessage message) { var attachments = new List <MimePart>(); var iter = new MimeIterator(message); // collect our list of attachments and their parent multiparts while (iter.MoveNext()) { var multipart = iter.Parent as Multipart; var part = iter.Current as MimePart; if (multipart != null && part != null && part.IsAttachment) { attachments.Add(part); } } return(attachments); }
/// <summary> /// Save the given message to the underlying storage system. /// </summary> /// <param name="context">The session context.</param> /// <param name="transaction">The SMTP message transaction to store.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>A unique identifier that represents this message in the underlying message store.</returns> public override Task <SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, CancellationToken cancellationToken) { Init(); var textMessage = (ITextMessage)transaction.Message; MimeMessage mailMessage = MimeMessage.Load(textMessage.Content); Message message = new Message(); message.Id = Guid.NewGuid(); message.RetryCount = 0; message.ErrorReason = ""; message.Timestamp = DateTime.UtcNow; var inboundMessage = new InboundMessage(); string fromAddress = String.Empty; if (mailMessage.From != null && mailMessage.From.Count > 0) { var from = ((MailboxAddress)mailMessage.From[0]); inboundMessage.From = from.Address; fromAddress = from.Address; inboundMessage.FromFull = new FromFull() { Email = from.Address, Name = from.Name }; } string toAddress = String.Empty; if (mailMessage.To != null && mailMessage.To.Count > 0) { inboundMessage.ToFull = new List <ToFull>(); foreach (var to in mailMessage.To) { var toAdd = (MailboxAddress)to; if (String.IsNullOrWhiteSpace(inboundMessage.To)) { inboundMessage.To = toAdd.Address; toAddress = toAdd.Address; } inboundMessage.ToFull.Add(new ToFull() { Email = toAdd.Address, Name = toAdd.Name }); } } _logger.Information("Email Received {id} {fromAddress} {toAddress}", message.Id, fromAddress, toAddress); var attachments = new List <MimePart>(); var multiparts = new List <Multipart>(); var iter = new MimeIterator(mailMessage); // collect our list of attachments and their parent multiparts while (iter.MoveNext()) { var multipart = iter.Parent as Multipart; var part = iter.Current as MimePart; if (multipart != null && part != null && part.IsAttachment) { // keep track of each attachment's parent multipart multiparts.Add(multipart); attachments.Add(part); } } // now remove each attachment from its parent multipart... for (int i = 0; i < attachments.Count; i++) { multiparts[i].Remove(attachments[i]); } inboundMessage.TextBody = mailMessage.GetTextBody(MimeKit.Text.TextFormat.Plain); inboundMessage.HtmlBody = mailMessage.HtmlBody; inboundMessage.Subject = mailMessage.Subject; inboundMessage.MessageID = mailMessage.MessageId; inboundMessage.Attachments = new List <Attachment>(); foreach (var attachment in attachments) { var att = new Attachment(); StreamReader reader = new StreamReader(attachment.Content.Stream); att.Content = reader.ReadToEnd(); att.Name = attachment.FileName; att.ContentID = attachment.ContentId; att.ContentType = attachment.ContentType.MimeType; inboundMessage.Attachments.Add(att); } message.InboundMessage = inboundMessage; var fileText = JsonConvert.SerializeObject(message); var filePath = _fileService.CreateFile($"{message.Id.ToString()}.rgm", "emails", fileText); if (!String.IsNullOrWhiteSpace(filePath)) { _logger.Information("Email Saved {id}", message.Id); return(Task.FromResult(SmtpResponse.Ok)); } else { _logger.Information("Email Not Saved {id}", message.Id); return(Task.FromResult(new SmtpResponse(SmtpReplyCode.MessageTimeout))); } }
public IList <EmailMessage> GetNewMessages(int accountId) { var account = _context.Accounts.Include(a => a.EmailAccount).FirstOrDefault(a => a.Id == accountId); var newMessages = new List <EmailMessage>(); if (account != null) { EmailAccount eAcc = account.EmailAccount; using (var client = new ImapClient()) { var credentials = new NetworkCredential(eAcc.UserName, eAcc.Password); client.Connect(eAcc.ServerUri, eAcc.ServerPort, eAcc.ServerUseSSL); client.AuthenticationMechanisms.Remove("XOAUTH2"); client.Authenticate(credentials); client.Inbox.Open(FolderAccess.ReadOnly); // Обрабатываем сами письма foreach (var summary in client.Inbox.Fetch((int)eAcc.LastMessageUid, -1, MessageSummaryItems.UniqueId)) { MimeMessage iMessage = client.Inbox.GetMessage(summary.UniqueId); // Если в белом списке есть запись "*", то принимаем письма от всех отправителей if (eAcc.WhileListFrom.Contains("*") || eAcc.WhileListFrom.Contains(iMessage.From.Mailboxes.First().Address)) { // Текстовое содержимое var message = new EmailMessage { Id = (int)summary.UniqueId.Id, From = iMessage.From.Mailboxes.First().Name, Subject = iMessage.Subject, Body = iMessage.TextBody, ReceivedDate = iMessage.Date.LocalDateTime }; // Вложения var multiparts = new List <Multipart>(); var attachments = new List <MimePart>(); using (var iter = new MimeIterator(iMessage)) { while (iter.MoveNext()) { var multipart = iter.Parent as Multipart; var part = iter.Current as MimePart; if (multipart != null && part != null && part.IsAttachment) { multiparts.Add(multipart); attachments.Add(part); } } } for (int i = 0; i < attachments.Count; i++) { multiparts[i].Remove(attachments[i]); } foreach (var attachment in attachments) { using (var ms = new MemoryStream()) { attachment.ContentObject.DecodeTo(ms); message.Attachments.Add(new Attachment { Title = attachment.FileName, Contents = ms.ToArray() }); } } newMessages.Add(message); } eAcc.LastMessageUid = (int)summary.UniqueId.Id; // Учитываем Id сообщения, даже если оно не подошло } } _context.SaveChanges(); } return(newMessages); }
public static void ExtractMainParts(this MailMessageData mail, MimeMessage message) { var htmlStream = new MemoryStream(); var textStream = new MemoryStream(); Action <MimeEntity> loadRealAttachment = (part) => { if ((part.ContentDisposition != null && !string.IsNullOrEmpty(part.ContentDisposition.FileName)) || part.ContentType != null && !string.IsNullOrEmpty(part.ContentType.Name)) { mail.LoadAttachments(new List <MimeEntity> { part }); } }; Action <MimePart> setBodyOrAttachment = (part) => { var entity = part as TextPart; if (htmlStream == null || textStream == null) { throw new Exception("Streams are not initialized"); } if ((entity == null || htmlStream.Length != 0 && entity.IsHtml || textStream.Length != 0 && !entity.IsHtml)) { loadRealAttachment(part); } else { if (mail.Introduction.Length < 200 && (!entity.IsHtml && !string.IsNullOrEmpty(entity.Text))) { if (string.IsNullOrEmpty(mail.Introduction)) { mail.Introduction = (entity.Text.Length > 200 ? entity.Text.Substring(0, 200) : entity.Text); } else { var need = 200 - mail.Introduction.Length; mail.Introduction += (entity.Text.Length > need ? entity.Text.Substring(0, need) : entity.Text); } mail.Introduction = mail.Introduction.Replace("\r\n", " ").Replace("\n", " ").Trim(); } var body = ConvertToHtml(entity); if (entity.IsHtml) { using (var sw = new StreamWriter(htmlStream, Encoding.UTF8, 1024, true)) { sw.Write(body); sw.Flush(); htmlStream.Seek(0, SeekOrigin.Begin); } } else { using (var sw = new StreamWriter(textStream, Encoding.UTF8, 1024, true)) { sw.Write(body); sw.Flush(); textStream.Seek(0, SeekOrigin.Begin); } } } }; var newPathIndex = ""; using (var sw = new StreamWriter(mail.HtmlBodyStream, Encoding.UTF8, 1024, true)) { using (var iter = new MimeIterator(message)) { while (string.IsNullOrEmpty(newPathIndex) ? iter.MoveNext() : iter.MoveTo(newPathIndex)) { if (!string.IsNullOrEmpty(newPathIndex)) { newPathIndex = ""; } var multipart = iter.Parent as Multipart; var part = iter.Current as MimePart; var subMessage = iter.Current as MessagePart; if (subMessage != null) { if ((subMessage.ContentDisposition != null && !string.IsNullOrEmpty(subMessage.ContentDisposition.FileName)) || subMessage.ContentType != null && !string.IsNullOrEmpty(subMessage.ContentType.Name)) { mail.LoadAttachments(new List <MimeEntity> { subMessage }, true); } else { subMessage.ContentDisposition = new ContentDisposition { Disposition = ContentDisposition.Attachment, FileName = "message.eml" }; mail.LoadAttachments(new List <MimeEntity> { subMessage }, true); } float pathIndex; if (float.TryParse(iter.PathSpecifier, out pathIndex)) { pathIndex++; newPathIndex = ((int)pathIndex).ToString(); continue; } } if (part == null || iter.Parent is MessagePart) { continue; } if (part.IsAttachment) { if (part is TnefPart) { var tnefPart = iter.Current as TnefPart; if (tnefPart != null) { mail.LoadAttachments(tnefPart.ExtractAttachments(), true); } } else { mail.LoadAttachments(new List <MimeEntity> { part }, multipart == null || !multipart.ContentType.MimeType.ToLowerInvariant().Equals("multipart/related")); } } else if (multipart != null) { switch (multipart.ContentType.MimeType.ToLowerInvariant()) { case "multipart/report": if (part is TextPart) { var entity = part as TextPart; if (entity == null) { entity = new TextPart(TextFormat.Plain); entity.SetText(Encoding.UTF8, part.ToString()); } var body = ConvertToHtml(entity); if (mail.HtmlBodyStream.Length == 0) { sw.Write(body); } else { sw.Write("<hr /><br/>"); sw.Write(body); } sw.Flush(); } else if (part is MessageDeliveryStatus) { var entity = new TextPart(TextFormat.Plain); var mds = (MessageDeliveryStatus)part; using (var memory = new MemoryStream()) { mds.Content.DecodeTo(memory); var text = Encoding.ASCII.GetString(memory.GetBuffer(), 0, (int)memory.Length) .Replace("\r\n", "\n"); entity.SetText(Encoding.UTF8, text); } var body = ConvertToHtml(entity); if (mail.HtmlBodyStream.Length == 0) { sw.Write(body); } else { sw.Write("<hr /><br/>"); sw.Write(body); } sw.Flush(); } else { loadRealAttachment(part); } break; case "multipart/mixed": if (part is TextPart) { var entity = part as TextPart; var body = ConvertToHtml(entity); if (mail.HtmlBodyStream.Length == 0) { sw.Write(body); } else { sw.Write("<hr /><br/>"); sw.Write(body); } sw.Flush(); } else { if (part.ContentType != null && part.ContentType.MediaType.Equals("image", StringComparison.InvariantCultureIgnoreCase) && part.ContentDisposition != null && part.ContentDisposition.Disposition.Equals(ContentDisposition.Inline, StringComparison.InvariantCultureIgnoreCase)) { if (string.IsNullOrEmpty(part.ContentId)) { part.ContentId = Guid.NewGuid().ToString("N").ToLower(); } mail.LoadAttachments(new List <MimeEntity> { part }); sw.Write("<hr /><br/>"); sw.Write("<img src=\"cid:{0}\">", part.ContentId); sw.Flush(); } else { loadRealAttachment(part); } } break; case "multipart/alternative": if (part is TextPart) { setBodyOrAttachment(part); } else { loadRealAttachment(part); } break; case "multipart/related": if (part is TextPart) { setBodyOrAttachment(part); } else if (!string.IsNullOrEmpty(part.ContentId) || part.ContentLocation != null) { mail.LoadAttachments(new List <MimeEntity> { part }); } else { loadRealAttachment(part); } break; default: if (part is TextPart) { setBodyOrAttachment(part); } else { loadRealAttachment(part); } break; } } else { if (part is TextPart) { setBodyOrAttachment(part); } else { loadRealAttachment(part); } } } } if (htmlStream.Length != 0) { if (mail.HtmlBodyStream.Length > 0) { sw.Write("<hr /><br/>"); sw.Flush(); } htmlStream.CopyTo(sw.BaseStream); } else if (textStream.Length != 0) { if (mail.HtmlBodyStream.Length == 0) { mail.TextBodyOnly = true; } else { sw.Write("<hr /><br/>"); sw.Flush(); } textStream.CopyTo(sw.BaseStream); } htmlStream.Dispose(); textStream.Dispose(); } if (mail.HtmlBodyStream.Length != 0) { return; } mail.HtmlBody = "<body><pre> </pre></body>"; mail.Introduction = ""; mail.TextBodyOnly = true; }
private void SetHtmlBodyAndIntroduction(MimeMessage message) { HtmlBody = "<br/>"; Introduction = ""; var htmlBodyBuilder = new StringBuilder().Append(message.HtmlBody); ContentType contentType = null; var subMessages = new ItemList <MimeMessage>(); var iter = new MimeIterator(message); while (iter.MoveNext()) { var multipart = iter.Parent as Multipart; var part = iter.Current as MimePart; var subMessage = iter.Current as MessagePart; if (multipart != null && part != null && !part.IsAttachment) { if (contentType == null && (part.ContentType.IsMimeType("text", "plain") || part.ContentType.IsMimeType("text", "html"))) { contentType = multipart.ContentType; } } if (subMessage != null) { subMessages.Add(subMessage.Message); } } contentType = contentType ?? message.Body.ContentType; if (contentType.MimeType.Equals("multipart/mixed", StringComparison.InvariantCultureIgnoreCase) && !string.IsNullOrEmpty(message.HtmlBody) && !string.IsNullOrEmpty(message.TextBody)) { htmlBodyBuilder.AppendFormat("<p>{0}</p>", MakeHtmlFromText(message.TextBody)); } else if (!string.IsNullOrEmpty(message.TextBody) && string.IsNullOrEmpty(message.HtmlBody)) { var html = MakeHtmlFromText(message.TextBody); htmlBodyBuilder.AppendFormat("<body><pre>{0}</pre></body>", html); TextBodyOnly = true; } foreach (var subMessage in subMessages) { var toString = string.Join(", ", subMessage.To.Select(s => s.ToString())); htmlBodyBuilder.Append("<hr /><br/>") .Append("<div style=\"padding-left:15px;\">") .AppendFormat("<span><b>Subject:</b> {0}</span><br/>", subMessage.Subject) .AppendFormat("<span><b>From:</b> {0}</span><br/>", subMessage.From) .AppendFormat("<span><b>Date:</b> {0}</span><br/>", subMessage.Date) .AppendFormat("<span><b>To:</b> {0}</span><br/></div>", toString) .AppendFormat("<br/>{0}", subMessage.HtmlBody); } HtmlBody = htmlBodyBuilder.ToString(); Introduction = GetIntroduction(HtmlBody); }
private void FillTreeView() { var iter = new MimeIterator(_mimeMessage); messageTree.BeginUpdate(); try { messageTree.Nodes.Clear(); TreeNode rootNode = null; while (iter.MoveNext()) { TreeNode createdNode = null; if (rootNode == null) { rootNode = messageTree.Nodes.Add(iter.Current.ContentId ?? "body"); createdNode = rootNode; } else { createdNode = rootNode.Nodes.Add(iter.Current.ContentId ?? "part"); } createdNode.Tag = iter.Current; createdNode.ContextMenu = new ContextMenu(); var menuItem = createdNode.ContextMenu.MenuItems.Add("Save to file..."); menuItem.Tag = iter.Current; menuItem.Click += (s, e) => { var dialog = new SaveFileDialog(); if (dialog.ShowDialog() == DialogResult.OK) { using (FileStream fs = new FileStream(dialog.FileName, FileMode.OpenOrCreate)) { if (((MenuItem)s).Tag is MimePart part) { if (part.ContentObject != null) { part.ContentObject.WriteTo(fs); } } fs.Flush(); } if (MessageBox.Show("Open now?", "Open attachment", MessageBoxButtons.YesNo) == DialogResult.Yes) { Process.Start(dialog.FileName); } } }; } if (rootNode != null) { rootNode.Expand(); messageTree.SelectedNode = rootNode; rootNode.EnsureVisible(); } } finally { messageTree.EndUpdate(); } }
static void DumpMimeTree (StringBuilder builder, MimeMessage message) { var iter = new MimeIterator (message); while (iter.MoveNext ()) { var ctype = iter.Current.ContentType; if (iter.Depth > 0) builder.Append (new string (' ', iter.Depth * 3)); builder.AppendFormat ("Content-Type: {0}/{1}", ctype.MediaType, ctype.MediaSubtype).Append ('\n'); } }
void HandlePgpMime(Outlook.MailItem mailItem, Outlook.Attachment encryptedMime, Outlook.Attachment sigMime, string sigHash = "sha1") { logger.Trace("> HandlePgpMime"); CryptoContext Context = null; byte[] cyphertext = null; byte[] clearbytes = null; var cleartext = mailItem.Body; // 1. Decrypt attachement if (encryptedMime != null) { logger.Trace("Decrypting cypher text."); var tempfile = Path.GetTempFileName(); encryptedMime.SaveAsFile(tempfile); cyphertext = File.ReadAllBytes(tempfile); File.Delete(tempfile); clearbytes = DecryptAndVerify(mailItem.To, cyphertext, out Context); if (clearbytes == null) return; cleartext = this._encoding.GetString(clearbytes); } // 2. Verify signature if (sigMime != null) { Context = new CryptoContext(PasswordCallback, _settings.Cipher, _settings.Digest); var Crypto = new PgpCrypto(Context); var mailType = mailItem.BodyFormat; try { logger.Trace("Verify detached signature"); var tempfile = Path.GetTempFileName(); sigMime.SaveAsFile(tempfile); var detachedsig = File.ReadAllText(tempfile); File.Delete(tempfile); // Build up a clearsignature format for validation // the rules for are the same with the addition of two heaer fields. // Ultimately we need to get these fields out of email itself. // NOTE: encoding could be uppercase or lowercase. Try both. // this is definetly hacky :/ var encoding = GetEncodingFromMail(mailItem); var body = string.Empty; // Try two different methods to get the mime body try { body = encoding.GetString( (byte[])mailItem.PropertyAccessor.GetProperty( "http://schemas.microsoft.com/mapi/string/{4E3A7680-B77A-11D0-9DA5-00C04FD65685}/Internet Charset Body/0x00000102")); } catch (Exception) { body = (string)mailItem.PropertyAccessor.GetProperty( "http://schemas.microsoft.com/mapi/proptag/0x1000001F"); // PR_BODY } var clearsigUpper = new StringBuilder(); clearsigUpper.Append(string.Format("-----BEGIN PGP SIGNED MESSAGE-----\r\nHash: {0}\r\nCharset: {1}\r\n\r\n", sigHash, encoding.BodyName.ToUpper())); clearsigUpper.Append("Content-Type: text/plain; charset="); clearsigUpper.Append(encoding.BodyName.ToUpper()); clearsigUpper.Append("\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n"); clearsigUpper.Append(PgpClearDashEscapeAndQuoteEncode(body)); clearsigUpper.Append("\r\n"); clearsigUpper.Append(detachedsig); var clearsigLower = new StringBuilder(clearsigUpper.Length); clearsigLower.Append(string.Format("-----BEGIN PGP SIGNED MESSAGE-----\r\nHash: {0}\r\nCharset: {1}\r\n\r\n", sigHash, encoding.BodyName.ToUpper())); clearsigLower.Append("Content-Type: text/plain; charset="); clearsigLower.Append(encoding.BodyName.ToLower()); clearsigLower.Append("\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n"); clearsigLower.Append(PgpClearDashEscapeAndQuoteEncode(body)); clearsigLower.Append("\r\n"); clearsigLower.Append(detachedsig); logger.Trace(clearsigUpper.ToString()); if (Crypto.VerifyClear(_encoding.GetBytes(clearsigUpper.ToString())) || Crypto.VerifyClear(_encoding.GetBytes(clearsigLower.ToString()))) { Context = Crypto.Context; var message = "** " + string.Format(Localized.MsgValidSig, Context.SignedByUserId, Context.SignedByKeyId) + "\n\n"; if (mailType == Outlook.OlBodyFormat.olFormatPlain) mailItem.Body = message + mailItem.Body; else mailItem.HTMLBody = AddMessageToHtmlBody(mailItem.HTMLBody, message); } else { Context = Crypto.Context; var message = "** " + string.Format(Localized.MsgInvalidSig, Context.SignedByUserId, Context.SignedByKeyId) + "\n\n"; if (mailType == Outlook.OlBodyFormat.olFormatPlain) mailItem.Body = message + mailItem.Body; else mailItem.HTMLBody = AddMessageToHtmlBody(mailItem.HTMLBody, message); } } catch (PublicKeyNotFoundException ex) { logger.Debug(ex.ToString()); Context = Crypto.Context; var message = "** " + Localized.MsgSigMissingPubKey + "\n\n"; if (mailType == Outlook.OlBodyFormat.olFormatPlain) mailItem.Body = message + mailItem.Body; else mailItem.HTMLBody = AddMessageToHtmlBody(mailItem.HTMLBody, message); } catch (Exception ex) { logger.Debug(ex.ToString()); WriteErrorData("VerifyEmail", ex); MessageBox.Show( ex.Message, Localized.ErrorDialogTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); } return; } if (Context == null) return; // Extract files from MIME data MimeMessage msg = null; TextPart textPart = null; MimeEntity htmlPart = null; var isHtml = false; using(var sin = new MemoryStream(clearbytes)) { var parser = new MimeParser(sin); msg = parser.ParseMessage(); var iter = new MimeIterator(msg); while(iter.MoveNext()) { var part = iter.Current as TextPart; if (part == null) continue; if (part.IsAttachment) continue; // message could include both text and html // if we find html use that over text. if (part.IsHtml) { htmlPart = part; isHtml = true; } else { textPart = part; } } } var DecryptAndVerifyHeaderMessage = "** "; if (Context.IsEncrypted) DecryptAndVerifyHeaderMessage += Localized.MsgDecrypt + " "; if (Context.FailedIntegrityCheck) DecryptAndVerifyHeaderMessage += Localized.MsgFailedIntegrityCheck + " "; if (Context.IsSigned && Context.SignatureValidated) { DecryptAndVerifyHeaderMessage += string.Format(Localized.MsgValidSig, Context.SignedByUserId, Context.SignedByKeyId); } else if (Context.IsSigned) { DecryptAndVerifyHeaderMessage += string.Format(Localized.MsgInvalidSig, Context.SignedByUserId, Context.SignedByKeyId); } else DecryptAndVerifyHeaderMessage += Localized.MsgUnsigned; DecryptAndVerifyHeaderMessage += "\n\n"; if(isHtml) { var htmlBody = msg.HtmlBody; var related = msg.Body as MultipartRelated; var doc = new HtmlAgilityPack.HtmlDocument(); var savedImages = new List<MimePart>(); doc.LoadHtml(htmlBody); // Find any embedded images foreach (var img in doc.DocumentNode.SelectNodes("//img[@src]")) { var src = img.Attributes["src"]; Uri uri; if (src == null || src.Value == null) continue; // parse the <img src=...> attribute value into a Uri if (Uri.IsWellFormedUriString(src.Value, UriKind.Absolute)) uri = new Uri(src.Value, UriKind.Absolute); else uri = new Uri(src.Value, UriKind.Relative); // locate the index of the attachment within the multipart/related (if it exists) string imageCid = src.Value.Substring(4); var iter = new MimeIterator(msg); MimePart attachment = null; while (iter.MoveNext()) { if (iter.Current.ContentId == imageCid) { attachment = iter.Current as MimePart; break; } } if (attachment == null) continue; string fileName; // save the attachment (if we haven't already saved it) if (!savedImages.Contains(attachment)) { fileName = attachment.FileName; if (string.IsNullOrEmpty(fileName)) fileName = Guid.NewGuid().ToString(); using (var stream = File.Create(fileName)) attachment.ContentObject.DecodeTo(stream); try { var att = mailItem.Attachments.Add(fileName, Outlook.OlAttachmentType.olEmbeddeditem, null, ""); att.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x3712001E", imageCid); savedImages.Add(attachment); } finally { // try not to leak temp files :) File.Delete(fileName); } } } mailItem.BodyFormat = Outlook.OlBodyFormat.olFormatHTML; mailItem.HTMLBody = AddMessageToHtmlBody(htmlBody, DecryptAndVerifyHeaderMessage); } else { // NOTE: For some reason we cannot change the BodyFormat once it's set. // So if we are set to HTML we need to wrap the plain text so it's // displayed okay. Also of course prevent XSS. if (mailItem.BodyFormat == Outlook.OlBodyFormat.olFormatPlain) { mailItem.Body = DecryptAndVerifyHeaderMessage + msg.TextBody; } else { var sb = new StringBuilder(msg.TextBody.Length + 100); sb.Append("<html><body><pre>"); sb.Append(WebUtility.HtmlEncode(DecryptAndVerifyHeaderMessage)); sb.Append(WebUtility.HtmlEncode(msg.TextBody)); sb.Append("</pre></body></html>"); mailItem.HTMLBody = sb.ToString(); } } // NOTE: Removing existing attachments is perminant, even if the message // is not saved. foreach (var mimeAttachment in msg.Attachments) { var fileName = mimeAttachment.FileName; var tempFile = Path.Combine(Path.GetTempPath(), fileName); using (var fout = File.OpenWrite(tempFile)) { mimeAttachment.ContentObject.DecodeTo(fout); } mailItem.Attachments.Add(tempFile, Outlook.OlAttachmentType.olByValue, 1, fileName); File.Delete(tempFile); } }
private void ExtractMainParts(MimeMessage message) { var htmlStream = new MemoryStream(); var textStream = new MemoryStream(); Action <MimeEntity> loadRealAttachment = (part) => { if ((part.ContentDisposition != null && !string.IsNullOrEmpty(part.ContentDisposition.FileName)) || part.ContentType != null && !string.IsNullOrEmpty(part.ContentType.Name)) { LoadAttachments(new List <MimeEntity> { part }); } }; Action <MimePart> setBodyOrAttachment = (part) => { var entity = part as TextPart; if (htmlStream == null || textStream == null) { throw new Exception("Streams are not initialized"); } if ((entity == null || htmlStream.Length != 0 && entity.IsHtml || textStream.Length != 0 && !entity.IsHtml)) { loadRealAttachment(part); } else { if (Introduction.Length < 200 && (!entity.IsHtml && !string.IsNullOrEmpty(entity.Text))) { if (string.IsNullOrEmpty(Introduction)) { Introduction = (entity.Text.Length > 200 ? entity.Text.Substring(0, 200) : entity.Text); } else { var need = 200 - Introduction.Length; Introduction += (entity.Text.Length > need ? entity.Text.Substring(0, need) : entity.Text); } Introduction = Introduction.Replace("\r\n", " ").Replace("\n", " ").Trim(); } var body = ConvertToHtml(entity); if (entity.IsHtml) { using (var sw = new StreamWriter(htmlStream, Encoding.UTF8, 1024, true)) { sw.Write(body); sw.Flush(); htmlStream.Seek(0, SeekOrigin.Begin); } } else { using (var sw = new StreamWriter(textStream, Encoding.UTF8, 1024, true)) { sw.Write(body); sw.Flush(); textStream.Seek(0, SeekOrigin.Begin); } } } }; using (var sw = new StreamWriter(HtmlBodyStream, Encoding.UTF8, 1024, true)) { using (var iter = new MimeIterator(message)) { while (iter.MoveNext()) { var multipart = iter.Parent as Multipart; var part = iter.Current as MimePart; var subMessage = iter.Current as MessagePart; if (subMessage != null) { if ((subMessage.ContentDisposition != null && !string.IsNullOrEmpty(subMessage.ContentDisposition.FileName)) || subMessage.ContentType != null && !string.IsNullOrEmpty(subMessage.ContentType.Name)) { LoadAttachments(new List <MimeEntity> { subMessage }, true); } else { subMessage.ContentDisposition = new ContentDisposition { Disposition = ContentDisposition.Attachment, FileName = "message.eml" }; LoadAttachments(new List <MimeEntity> { subMessage }, true); } } if (part == null) { continue; } if (part.IsAttachment) { if (part is TnefPart) { var tnefPart = iter.Current as TnefPart; if (tnefPart != null) { LoadAttachments(tnefPart.ExtractAttachments(), true); } } else { LoadAttachments(new List <MimeEntity> { part }, multipart == null || !multipart.ContentType.MimeType.ToLowerInvariant().Equals("multipart/related")); } } else if (multipart != null) { switch (multipart.ContentType.MimeType.ToLowerInvariant()) { case "multipart/mixed": if (part is TextPart) { var entity = part as TextPart; var body = ConvertToHtml(entity); if (HtmlBodyStream.Length == 0) { sw.Write(body); } else { sw.Write("<hr /><br/>"); sw.Write(body); } sw.Flush(); } else { if (part.ContentType.MediaType.Equals("image", StringComparison.InvariantCultureIgnoreCase) && part.ContentDisposition.Disposition == ContentDisposition.Inline) { if (string.IsNullOrEmpty(part.ContentId)) { part.ContentId = Guid.NewGuid().ToString("N").ToLower(); } LoadAttachments(new List <MimeEntity> { part }); sw.Write("<hr /><br/>"); sw.Write("<img src=\"cid:{0}\">", part.ContentId); sw.Flush(); } else { loadRealAttachment(part); } } break; case "multipart/alternative": if (part is TextPart) { setBodyOrAttachment(part); } else { loadRealAttachment(part); } break; case "multipart/related": if (part is TextPart) { setBodyOrAttachment(part); } else if (!string.IsNullOrEmpty(part.ContentId) || part.ContentLocation != null) { LoadAttachments(new List <MimeEntity> { part }); } else { loadRealAttachment(part); } break; default: if (part is TextPart) { setBodyOrAttachment(part); } else { loadRealAttachment(part); } break; } } else { if (part is TextPart) { setBodyOrAttachment(part); } else { loadRealAttachment(part); } } } } if (htmlStream.Length != 0) { if (HtmlBodyStream.Length > 0) { sw.Write("<hr /><br/>"); sw.Flush(); } htmlStream.CopyTo(sw.BaseStream); } else if (textStream.Length != 0) { if (HtmlBodyStream.Length == 0) { TextBodyOnly = true; } else { sw.Write("<hr /><br/>"); sw.Flush(); } textStream.CopyTo(sw.BaseStream); } htmlStream.Dispose(); textStream.Dispose(); } if (HtmlBodyStream.Length != 0) { return; } HtmlBody = "<body><pre> </pre></body>"; Introduction = ""; TextBodyOnly = true; }