Click or drag to resize
MimeKit

ITextPart Interface

An interface for a textual MIME part.

Namespace: MimeKit
Assembly: MimeKit (in MimeKit.dll) Version: 4.7.1
Syntax
C#
public interface ITextPart : IMimePart, 
	IMimeEntity, IDisposable

The ITextPart type exposes the following members.

Properties
 NameDescription
Public propertyCode exampleContent Get or set the MIME content.
(Inherited from IMimePart)
Public propertyContentBase Get or set the base content URI.
(Inherited from IMimeEntity)
Public propertyContentDescription Get or set the description of the content if available.
(Inherited from IMimePart)
Public propertyContentDisposition Get or set the content disposition.
(Inherited from IMimeEntity)
Public propertyContentDuration Get or set the duration of the content if available.
(Inherited from IMimePart)
Public propertyContentId Get or set the Content-Id.
(Inherited from IMimeEntity)
Public propertyContentLocation Get or set the content location.
(Inherited from IMimeEntity)
Public propertyContentMd5 Get or set the md5sum of the content.
(Inherited from IMimePart)
Public propertyContentTransferEncoding Get or set the content transfer encoding.
(Inherited from IMimePart)
Public propertyContentType Get the type of the content.
(Inherited from IMimeEntity)
Public propertyCode exampleFileName Get or set the name of the file.
(Inherited from IMimePart)
Public propertyFormat Get the text format of the content.
Public propertyHeaders Get the list of headers.
(Inherited from IMimeEntity)
Public propertyIsAttachment Get a value indicating whether this entity is an attachment.
(Inherited from IMimeEntity)
Public propertyIsEnriched Get whether or not this text part contains enriched text.
Public propertyCode exampleIsFlowed Get whether or not this text part contains flowed text.
Public propertyCode exampleIsHtml Get whether or not this text part contains HTML.
Public propertyIsPlain Get whether or not this text part contains plain text.
Public propertyIsRichText Get whether or not this text part contains RTF.
Public propertyText Get the decoded text content.
Top
Methods
 NameDescription
Public methodAccept Dispatches to the specific visit method for this MIME entity.
(Inherited from IMimeEntity)
Public methodComputeContentMd5 Compute the MD5 checksum of the content.
(Inherited from IMimePart)
Public methodDispose
(Inherited from IDisposable)
Public methodGetBestEncoding(EncodingConstraint, CancellationToken) Calculate the most efficient content encoding given the specified constraint.
(Inherited from IMimePart)
Public methodGetBestEncoding(EncodingConstraint, Int32, CancellationToken) Calculate the most efficient content encoding given the specified constraint.
(Inherited from IMimePart)
Public methodGetText(Encoding) Get the decoded text content using the provided charset encoding to override the charset specified in the Content-Type parameters.
Public methodGetText(Encoding) Get the decoded text and the encoding used to convert it into unicode.
Public methodGetText(String) Get the decoded text content using the provided charset to override the charset specified in the Content-Type parameters.
Public methodPrepare Prepare the MIME entity for transport using the specified encoding constraints.
(Inherited from IMimeEntity)
Public methodSetText(Encoding, String) Set the text content and the charset parameter in the Content-Type header.
Public methodSetText(String, String) Set the text content and the charset parameter in the Content-Type header.
Public methodTryDetectEncoding Try to detect the encoding of the text content.
Public methodVerifyContentMd5 Verify the Content-Md5 value against an independently computed md5sum.
(Inherited from IMimePart)
Public methodWriteTo(Stream, CancellationToken) Write the IMimeEntity to the specified output stream.
(Inherited from IMimeEntity)
Public methodWriteTo(String, CancellationToken) Write the IMimeEntity to the specified file.
(Inherited from IMimeEntity)
Public methodWriteTo(FormatOptions, Stream, CancellationToken) Write the IMimeEntity to the specified output stream.
(Inherited from IMimeEntity)
Public methodWriteTo(FormatOptions, String, CancellationToken) Write the IMimeEntity to the specified file.
(Inherited from IMimeEntity)
Public methodWriteTo(Stream, Boolean, CancellationToken) Write the IMimeEntity to the specified output stream.
(Inherited from IMimeEntity)
Public methodWriteTo(String, Boolean, CancellationToken) Write the IMimeEntity to the specified file.
(Inherited from IMimeEntity)
Public methodWriteTo(FormatOptions, Stream, Boolean, CancellationToken) Write the IMimeEntity to the specified output stream.
(Inherited from IMimeEntity)
Public methodWriteTo(FormatOptions, String, Boolean, CancellationToken) Write the IMimeEntity to the specified file.
(Inherited from IMimeEntity)
Public methodWriteToAsync(Stream, CancellationToken) Asynchronously write the IMimeEntity to the specified output stream.
(Inherited from IMimeEntity)
Public methodWriteToAsync(String, CancellationToken) Asynchronously write the IMimeEntity to the specified file.
(Inherited from IMimeEntity)
Public methodWriteToAsync(FormatOptions, Stream, CancellationToken) Asynchronously write the IMimeEntity to the specified output stream.
(Inherited from IMimeEntity)
Public methodWriteToAsync(FormatOptions, String, CancellationToken) Asynchronously write the IMimeEntity to the specified file.
(Inherited from IMimeEntity)
Public methodWriteToAsync(Stream, Boolean, CancellationToken) Asynchronously write the IMimeEntity to the specified output stream.
(Inherited from IMimeEntity)
Public methodWriteToAsync(String, Boolean, CancellationToken) Asynchronously write the IMimeEntity to the specified file.
(Inherited from IMimeEntity)
Public methodWriteToAsync(FormatOptions, Stream, Boolean, CancellationToken) Asynchronously write the IMimeEntity to the specified output stream.
(Inherited from IMimeEntity)
Public methodWriteToAsync(FormatOptions, String, Boolean, CancellationToken) Asynchronously write the IMimeEntity to the specified file.
(Inherited from IMimeEntity)
Top
Remarks

Unless overridden, all textual parts parsed by the MimeParser, such as text/plain or text/html, will be represented by a TextPart.

For more information about text media types, see section 4.1 of rfc2046.

Example
C#
/// <summary>
/// Visits a MimeMessage and generates HTML suitable to be rendered by a browser control.
/// </summary>
class HtmlPreviewVisitor : MimeVisitor
{
    List<MultipartRelated> stack = new List<MultipartRelated> ();
    List<MimeEntity> attachments = new List<MimeEntity> ();
    string body;

    /// <summary>
    /// Creates a new HtmlPreviewVisitor.
    /// </summary>
    public HtmlPreviewVisitor ()
    {
    }

    /// <summary>
    /// The list of attachments that were in the MimeMessage.
    /// </summary>
    public IList<MimeEntity> Attachments {
        get { return attachments; }
    }

    /// <summary>
    /// The HTML string that can be set on the BrowserControl.
    /// </summary>
    public string HtmlBody {
        get { return body ?? string.Empty; }
    }

    protected override void VisitMultipartAlternative (MultipartAlternative alternative)
    {
        // walk the multipart/alternative children backwards from greatest level of faithfulness to the least faithful
        for (int i = alternative.Count - 1; i >= 0 && body == null; i--)
            alternative[i].Accept (this);
    }

    protected override void VisitMultipartRelated (MultipartRelated related)
    {
        var root = related.Root;

        // push this multipart/related onto our stack
        stack.Add (related);

        // visit the root document
        root.Accept (this);

        // pop this multipart/related off our stack
        stack.RemoveAt (stack.Count - 1);
    }

    // look up the image based on the img src url within our multipart/related stack
    bool TryGetImage (string url, out MimePart image)
    {
        UriKind kind;
        int index;
        Uri uri;

        if (Uri.IsWellFormedUriString (url, UriKind.Absolute))
            kind = UriKind.Absolute;
        else if (Uri.IsWellFormedUriString (url, UriKind.Relative))
            kind = UriKind.Relative;
        else
            kind = UriKind.RelativeOrAbsolute;

        try {
            uri = new Uri (url, kind);
        } catch {
            image = null;
            return false;
        }

        for (int i = stack.Count - 1; i >= 0; i--) {
            if ((index = stack[i].IndexOf (uri)) == -1)
                continue;

            image = stack[i][index] as MimePart;
            return image != null;
        }

        image = null;

        return false;
    }

    /// <summary>
    /// Get a data: URI for the image attachment.
    /// </summary>
    /// <remarks>
    /// Encodes the image attachment into a string suitable for setting as a src= attribute value in
    /// an img tag.
    /// </remarks>
    /// <returns>The data: URI.</returns>
    /// <param name="image">The image attachment.</param>
    string GetDataUri (MimePart image)
    {
        using (var memory = new MemoryStream ()) {
            image.Content.DecodeTo (memory);
            var buffer = memory.GetBuffer ();
            var length = (int) memory.Length;
            var base64 = Convert.ToBase64String (buffer, 0, length);

            return string.Format ("data:{0};base64,{1}", image.ContentType.MimeType, base64);
        }
    }

    // Replaces <img src=...> urls that refer to images embedded within the message with
    // "file://" urls that the browser control will actually be able to load.
    void HtmlTagCallback (HtmlTagContext ctx, HtmlWriter htmlWriter)
    {
        if (ctx.TagId == HtmlTagId.Meta && !ctx.IsEndTag) {
            bool isContentType = false;

            ctx.WriteTag (htmlWriter, false);

            // replace charsets with "utf-8" since our output will be in utf-8 (and not whatever the original charset was)
            foreach (var attribute in ctx.Attributes) {
                if (attribute.Id == HtmlAttributeId.Charset) {
                    htmlWriter.WriteAttributeName (attribute.Name);
                    htmlWriter.WriteAttributeValue ("utf-8");
                } else if (isContentType && attribute.Id == HtmlAttributeId.Content) {
                    htmlWriter.WriteAttributeName (attribute.Name);
                    htmlWriter.WriteAttributeValue ("text/html; charset=utf-8");
                } else {
                    if (attribute.Id == HtmlAttributeId.HttpEquiv && attribute.Value != null
                        && attribute.Value.Equals ("Content-Type", StringComparison.OrdinalIgnoreCase))
                        isContentType = true;

                    htmlWriter.WriteAttribute (attribute);
                }
            }
        } else if (ctx.TagId == HtmlTagId.Image && !ctx.IsEndTag && stack.Count > 0) {
            ctx.WriteTag (htmlWriter, false);

            // replace the src attribute with a "data:" URL
            foreach (var attribute in ctx.Attributes) {
                if (attribute.Id == HtmlAttributeId.Src) {
                    if (!TryGetImage (attribute.Value, out var image)) {
                        htmlWriter.WriteAttribute (attribute);
                        continue;
                    }

                    var dataUri = GetDataUri (image);

                    htmlWriter.WriteAttributeName (attribute.Name);
                    htmlWriter.WriteAttributeValue (dataUri);
                } else {
                    htmlWriter.WriteAttribute (attribute);
                }
            }
        } else if (ctx.TagId == HtmlTagId.Body && !ctx.IsEndTag) {
            ctx.WriteTag (htmlWriter, false);

            // add and/or replace oncontextmenu="return false;"
            foreach (var attribute in ctx.Attributes) {
                if (attribute.Name.Equals ("oncontextmenu", StringComparison.OrdinalIgnoreCase))
                    continue;

                htmlWriter.WriteAttribute (attribute);
            }

            htmlWriter.WriteAttribute ("oncontextmenu", "return false;");
        } else {
            // pass the tag through to the output
            ctx.WriteTag (htmlWriter, true);
        }
    }

    protected override void VisitTextPart (TextPart entity)
    {
        TextConverter converter;

        if (body != null) {
            // since we've already found the body, treat this as an attachment
            attachments.Add (entity);
            return;
        }

        if (entity.IsHtml) {
            converter = new HtmlToHtml {
                HtmlTagCallback = HtmlTagCallback
            };
        } else if (entity.IsFlowed) {
            var flowed = new FlowedToHtml ();
            string delsp;

            if (entity.ContentType.Parameters.TryGetValue ("delsp", out delsp))
                flowed.DeleteSpace = delsp.Equals ("yes", StringComparison.OrdinalIgnoreCase);

            converter = flowed;
        } else {
            converter = new TextToHtml ();
        }

        body = converter.Convert (entity.Text);
    }

    protected override void VisitTnefPart (TnefPart entity)
    {
        // extract any attachments in the MS-TNEF part
        attachments.AddRange (entity.ExtractAttachments ());
    }

    protected override void VisitMessagePart (MessagePart entity)
    {
        // treat message/rfc822 parts as attachments
        attachments.Add (entity);
    }

    protected override void VisitMimePart (MimePart entity)
    {
        // realistically, if we've gotten this far, then we can treat this as an attachment
        // even if the IsAttachment property is false.
        attachments.Add (entity);
    }
}
See Also