/// <summary> /// Load a <see cref="MimeEntity"/> from the specified content stream. /// </summary> /// <remarks> /// This method is mostly meant for use with APIs such as <see cref="System.Net.HttpWebResponse"/> /// where the headers are parsed separately from the content. /// </remarks> /// <returns>The parsed MIME entity.</returns> /// <param name="options">The parser options.</param> /// <param name="contentType">The Content-Type of the stream.</param> /// <param name="content">The content stream.</param> /// <param name="cancellationToken">A cancellation token.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="options"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="contentType"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="content"/> is <c>null</c>.</para> /// </exception> /// <exception cref="System.OperationCanceledException"> /// The operation was canceled via the cancellation token. /// </exception> /// <exception cref="System.FormatException"> /// There was an error parsing the entity. /// </exception> /// <exception cref="System.IO.IOException"> /// An I/O error occurred. /// </exception> public static MimeEntity Load(ParserOptions options, ContentType contentType, Stream content, CancellationToken cancellationToken = default(CancellationToken)) { if (options == null) { throw new ArgumentNullException("options"); } if (contentType == null) { throw new ArgumentNullException("contentType"); } if (content == null) { throw new ArgumentNullException("content"); } var format = FormatOptions.CloneDefault(); format.NewLineFormat = NewLineFormat.Dos; var encoded = contentType.Encode(format, Encoding.UTF8); var header = string.Format("Content-Type:{0}\r\n", encoded); var chained = new ChainedStream(); chained.Add(new MemoryStream(Encoding.UTF8.GetBytes(header), false)); chained.Add(content); return(Load(options, chained, cancellationToken)); }
/// <summary> /// Splits the specified message into multiple messages. /// </summary> /// <remarks> /// Splits the specified message into multiple messages, each with a /// message/partial body no larger than the max size specified. /// </remarks> /// <returns>An enumeration of partial messages.</returns> /// <param name="message">The message.</param> /// <param name="maxSize">The maximum size for each message body.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="message"/> is <c>null</c>. /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// <paramref name="maxSize"/> is less than <c>1</c>. /// </exception> public static IEnumerable <MimeMessage> Split(MimeMessage message, int maxSize) { if (message == null) { throw new ArgumentNullException(nameof(message)); } if (maxSize < 1) { throw new ArgumentOutOfRangeException(nameof(maxSize)); } var options = FormatOptions.CloneDefault(); foreach (HeaderId id in Enum.GetValues(typeof(HeaderId))) { switch (id) { case HeaderId.Subject: case HeaderId.MessageId: case HeaderId.Encrypted: case HeaderId.MimeVersion: case HeaderId.ContentAlternative: case HeaderId.ContentBase: case HeaderId.ContentClass: case HeaderId.ContentDescription: case HeaderId.ContentDisposition: case HeaderId.ContentDuration: case HeaderId.ContentFeatures: case HeaderId.ContentId: case HeaderId.ContentIdentifier: case HeaderId.ContentLanguage: case HeaderId.ContentLength: case HeaderId.ContentLocation: case HeaderId.ContentMd5: case HeaderId.ContentReturn: case HeaderId.ContentTransferEncoding: case HeaderId.ContentTranslationType: case HeaderId.ContentType: break; default: options.HiddenHeaders.Add(id); break; } } var memory = new MemoryStream(); message.WriteTo(options, memory); memory.Seek(0, SeekOrigin.Begin); if (memory.Length <= maxSize) { memory.Dispose(); yield return(message); yield break; } var streams = new List <Stream> (); #if !NETSTANDARD1_3 && !NETSTANDARD1_6 var buf = memory.GetBuffer(); #else var buf = memory.ToArray(); #endif long startIndex = 0; while (startIndex < memory.Length) { // Preferably, we'd split on whole-lines if we can, // but if that's not possible, split on max size long endIndex = Math.Min(memory.Length, startIndex + maxSize); if (endIndex < memory.Length) { long ebx = endIndex; while (ebx > (startIndex + 1) && buf[ebx] != (byte)'\n') { ebx--; } if (buf[ebx] == (byte)'\n') { endIndex = ebx + 1; } } streams.Add(new BoundStream(memory, startIndex, endIndex, true)); startIndex = endIndex; } var msgid = message.MessageId ?? MimeUtils.GenerateMessageId(); int number = 1; foreach (var stream in streams) { var part = new MessagePartial(msgid, number++, streams.Count) { Content = new MimeContent(stream) }; var submessage = CloneMessage(message); submessage.MessageId = MimeUtils.GenerateMessageId(); submessage.Body = part; yield return(submessage); } yield break; }