More .NET components

MIME and MailMessage

High-level MailMessage API #

Rebex.Mail.MailMessage class represents an email message. It provides a simple high-level API and supports numerous mail message formats.

CSharp

// create Mail message
var message = new Rebex.Mail.MailMessage();

// fill some fields
message.From = "alice@example.org";
message.To = "bobr@example.org";
message.Subject = "Test";

// add text and HTML bodies
message.BodyText = "This is plain-text body.";
message.BodyHtml = "This is <strong>HTML</strong> body.";

// save message
message.Save(@"C:\MyData\mail.eml");

// send message
Smtp.Send(message, smtpServer);

VisualBasic

' create Mail message
Dim message = New Rebex.Mail.MailMessage()

' fill some fields
message.From = "alice@example.org"
message.To = "bob@example.org"
message.Subject = "Test"

' add text and HTML bodies
message.BodyText = "This is plain-text body."
message.BodyHtml = "This is <strong>HTML</strong> body."

' save message
message.Save("C:\MyData\mail.eml")

'send message
Smtp.Send(message, smtpServer)
If you need to work directly with MIME entities, content parts and to deal with similar low level issues you can use MimeMessage class.

Support for many email formats #

Rebex Secure Mail supports the following message formats:

  • RFC 822/2822/5322 - Internet Message Format (often uses the '.eml' extension).
  • MIME - Multipurpose Internet Mail Extensions. Adds support for attachments, HTML bodies, etc.
  • UUEncode - legacy email extension. Adds support for attachments.
  • Outlook MSG - MS Outlook native format (uses '.msg' extension).
  • MS-TNEF - Microsoft's proprietary email extension format (also known as 'winmail.dat', a name used by its container attachments).

Note: MailMessage class supports all of these formats. MimeMessage only supports MIME and RFC 822/2822/5322. Visit labs.rebex.net for downloading OutlookMessage class which allows you to work with Outlook .msg messages directly.

Saving and loading #

MailMessage and MimeMessage objects can be easily saved to a disk or a stream.

The MailMessage object is saved in MIME format by default, but also supports Outlook MSG format.
The MimeMessage object only supports the MIME format.

CSharp

// create mail
var mail = new Rebex.Mail.MailMessage();
// fill some fields
// ...

// save mail to disk in MIME format
mail.Save(@"C:\MyData\mail.eml");

// save mail to stream in MIME format
var stream = new MemoryStream();
mail.Save(stream);

VisualBasic

' create mail
Dim mail = New Rebex.Mail.MailMessage()
' fill some fields
' ...

' save mail to disk
mail.Save("C:\MyData\mail.eml")

' save mail to stream
Dim stream = New MemoryStream()
mail.Save(stream)

An existing mail message can be loaded from a disk or a stream.

MailMessage object detects the message format automatically.
MimeMessage object only supports the MIME format.

CSharp

// load mail from disk
var mail1 = new Rebex.Mail.MailMessage();
mail1.Load(@"C:\MyData\mail.eml");

// load mail from stream
var mail2 = new Rebex.Mail.MailMessage();
mail2.Load(stream);

VisualBasic

' load mail from disk
Dim mail1 = New Rebex.Mail.MailMessage()
mail1.Load("C:\MyData\mail.eml")

' load mail from stream
Dim mail2 = New Rebex.Mail.MailMessage()
mail2.Load(stream)

Note: When using MailMessage.Load and MailMessage.Save to load and save a single mail message, you might not end up with an exact copy of the original message. The copy will be equivalent to original, but its structure and headers might have been changed (normalized).
Additionally, when loading and saving Outlook MSG, some non-MIME headers may be lost (if necessary, you can prevent losing some headers by setting enabling MailMessage.Options' LoadMsgProperties).

Saving to MIME and Outlook MSG formats #

To save an instance of MailMessage object in specific format, use the MailFormat argument:

CSharp

// create mail
var mail = new Rebex.Mail.MailMessage();
// fill some fields
// ...

// save mail as MIME message
mail.Save(@"C:\MyData\mail.eml", MailFormat.Mime);

// save mail as Outlook MSG message
mail.Save(@"C:\MyData\mail.msg", MailFormat.OutlookMsg);

VisualBasic

' create mail
Dim mail = New Rebex.Mail.MailMessage()
' fill some fields
' ...

' save mail as MIME message
mail.Save("C:\MyData\mail.eml", MailFormat.Mime)

' save mail as Outlook MSG message
mail.Save("C:\MyData\mail.msg", MailFormat.OutlookMsg)

Plain text messages #

Plain text messages only contain a single 'text/plain' body and no attachments or resources. To create such message, only set the MailMessage.BodyText property:

CSharp

// create mail
var mail = new Rebex.Mail.MailMessage();
// fill some fields
// ...

// add plain-text body
mail.BodyText = "This is a plain-text body.";

VisualBasic

' create mail
Dim mail = New Rebex.Mail.MailMessage()
' fill some fields
' ...

' add plain-text body
mail.BodyText = "This is a plain-text body."

HTML messages #

HTML messages contains a 'text/html' body. To create such message, set the MailMessage.BodyHtml property:

CSharp

// create mail
var mail = new Rebex.Mail.MailMessage();
// fill some fields
// ...

// add HTML body
mail.BodyHtml = "This is an <strong>HTML</strong> body.";

VisualBasic

' create mail
Dim mail = New Rebex.Mail.MailMessage()
' fill some fields
' ...

' add HTML body
mail.BodyHtml = "This is an <strong>HTML</strong> body."

Note: It's recommended to set BodyText property as well to a plain text version of the HTML text. This makes the message compatible recipients that don't support HTML or prefer plain text.

Attachments #

To add an attachment to a mail message, use the Add method on the MailMessage.Attachments collection. It is recommended to specify attachment's content type as well to make it possible for the receiving application to determine the attachment kind. Some e-mail clients require this to display the attachments correctly.

CSharp

// create mail
var mail = new Rebex.Mail.MailMessage();

// add an attachment
var attachment = new Attachment(@"C:\MyData\file.txt", null, Rebex.Mail.MediaTypeNames.Text.Plain);
mail.Attachments.Add(attachment);

VisualBasic

' create mail
Dim mail = New Rebex.Mail.MailMessage()

' add an attachment
Dim attachment = New Attachment("C:\MyData\file.txt", Nothing, Rebex.Mail.MediaTypeNames.Text.Plain)
mail.Attachments.Add(attachment)

On the other side, when you are the receiver of the mail message, you can access to messages attachments through MailMessage.Attachments collection and read useful properties from the Attachment object:

CSharp

// print some info about mail attachments
Console.WriteLine("Attachments: {0}", mail.Attachments.Count);
foreach (Attachment att in mail.Attachments)
{
    Console.WriteLine("{0} ({1}) [{2} B]",
        att.FileName, att.ContentType.MediaType, att.GetContentLength());
}

VisualBasic

' print some info about mail attachments
Console.WriteLine("Attachments: {0}", mail.Attachments.Count)
For Each att As Attachment In mail.Attachments
    Console.WriteLine("{0} ({1}) [{2} B]",
        att.FileName, att.ContentType.MediaType, att.GetContentLength())
Next

Note: A special kind of attachments are called 'resources' and can be found in MailMessage.Resources collection that resembles the Attachments collection. Unlike attachments, resources are supposed to contain embedded images and/or other media used by one of the message bodies (typically the HTML body).

Embedded messages #

In addition to ordinary attachments that represent an attached file, Rebex Secure Mail supports attached messages. Unlike ordinary attachments, these are parsed as MailMessage or MimeMessage objects and are accessible through Attachment object's ContentMessage property.

CSharp

// create mail message
var mail = new Rebex.Mail.MailMessage();
mail.Subject = "Mail message";
// ...

// create mail message to be embedded
var embedded = new Rebex.Mail.MailMessage();
embedded.Subject = "Embedded message";
// ...

// add the embedded message as an attachment
mail.Attachments.Add(new Attachment(embedded));

VisualBasic

' create mail message
Dim mail = New Rebex.Mail.MailMessage
mail.Subject = "Mail message"
' ...

' create mail message to be embedded
Dim embedded = New Rebex.Mail.MailMessage
embedded.Subject = "Embedded message"
' ...

' add the embedded message as an attachment
mail.Attachments.Add(New Attachment(embedded))

Creating replies #

MailMessage.CreateReply method makes it possible to easily create a reply to a specified message - it transfers the appropriate headers for you:

CSharp

// download a message to reply to
MailMessage original = imap.GetMailMessage(uniqueId);

// reply to all
MailMessage reply = original.CreateReply("joe@example.org", ReplyBodyTransformation.None, true);
reply.BodyText = "Hello, I agree.\n" + original.BodyText;

// send the reply
smtp.Send(reply);

VisualBasic

' download a message to reply to
Dim original As MailMessage = imap.GetMailMessage(uniqueId)

' reply to all
Dim reply As MailMessage = original.CreateReply("joe@example.org", ReplyBodyTransformation.None, True)
reply.BodyText = "Hello, I agree.\n" & original.BodyText

' send the reply
smtp.Send(reply)

Custom headers #

Message headers are commonly used to store various e-mail metadata (such as spam filtering score or mail agent name). Both built-in and custom message headers can be accessed and manipulated using the Headers collection, available in both MailMessage and MimeMessage objects.

For example, to request delivery notification from the recipient, add the Disposition-Notification-To header before sending the message:

CSharp

// create a new message
var mail = new MailMessage();

// initialize it
mail.From = "joe@example.org";
mail.To = "john@example.org";

// and request the read receipt
mail.Headers.Add("Disposition-Notification-To", "joe@example.org");

VisualBasic

' create a new message
Dim mail = New MailMessage()

' initialize it
mail.From = "joe@example.org"
mail.To = "john@example.org"

' and request the read receipt
mail.Headers.Add("Disposition-Notification-To", "joe@example.org")

Note: Not all mail clients support DSN requests and most of those that do ask the user for permission before sending them.

Mail body views and resources #

A mail message can contain couple of alternate views of the message body. The most common case is that the message contains a formated HTML body and a plain-text body. These two views can be accessed with MailMessage.BodyText and MailMessage.BodyHtml properties.

However, if you need more control over the views or if you need to work with views that are not HTML or plain-text, the MailMessage object provides AlternateViews collection (see RTF to HTML convertor sample code).

In addition to AlternateViews, the MailMessage object provides a related Resources collection. It is simmilar to Attachments collection, but contains items linked from within the HTML body (such as embedded images).

Embedding images into HTML messages #

Embedding an image into an HTML message consists of three steps:

  1. Generate a CID (content ID) to identify the image.
  2. Include <img src='cid:ImageId' /> element within the HTML body.
  3. Add the image to collection of linked resources, with its Content-ID set.

CSharp

// create mail
var mail = new Rebex.Mail.MailMessage();
// fill some fields
// ...

// generate a content ID for the image
string imageId = "image001@rebex.net";

// add HTML body
mail.BodyHtml = string.Format("This is embedded image: <img src='cid:{0}'/>", imageId);

// add image to linked resources
var resource = new Rebex.Mail.LinkedResource(
    @"C:\MyData\image.jpg", Rebex.Mail.MediaTypeNames.Image.Jpeg);
resource.ContentId = imageId;

mail.Resources.Add(resource);

VisualBasic

' create mail
Dim mail = New Rebex.Mail.MailMessage()
' fill some fields
' ...

' generate a content ID for the image
Dim imageId = "image001@rebex.net"

' add HTML body
mail.BodyHtml = String.Format("This is embedded image: <img src='cid:{0}'/>", imageId)

' add image to linked resources
Dim resource = New Rebex.Mail.LinkedResource(
               "C:\MyData\image.jpg", Rebex.Mail.MediaTypeNames.Image.Jpeg)
resource.ContentId = imageId

mail.Resources.Add(resource)

Loading TNEF/winmail.dat messages #

Microsoft Outlook makes it possible to create a mail message in three formats: plain text, HTML and RTF.

Unlike plain text and HTML, a RTF message is created in proprietary format called MS-TNEF, which is also known as winmail.dat. It is a MIME message with a single attachment (called 'winmail.dat' or 'win.dat') that contains the actual content of the message (the RTF body and all attached objects) in a non-standard format that is notorious for being incomatible with a large number of third-party email clients.

When loading a message to MailMessage object, the attached MS-TNEF file is parsed and the whole message is converted into a standard MIME format. Because almost no third-party email clients supports MIME messages with RTF bodies, the MailMessage object converts the RTF body to HTML and adds both forms to MailMessage.AlternateViews collection (as "text/rtf" and "text/hmtl", which is accessible through MailMessage.BodyHtml). The original attached objects from winmail.dat are made accessible by MailMessage.Attachments collection as common attachments.

Following code shows, how to load MS-TNEF message, get the RTF body and its HTML equivalent:

CSharp

// load TNEF mail
var mail = new Rebex.Mail.MailMessage();
mail.Load(@"C:\MyData\TNEF-mail.eml");

// get the HTML equivalent of RTF body
string html = mail.BodyHtml;

// find the original RTF body
string rtf = null;
foreach (AlternateView view in mail.AlternateViews)
{
    if (view.ContentType.MediaType == Rebex.Mail.MediaTypeNames.Text.Rtf)
        rtf = view.ContentString;
}

VisualBasic

' load TNEF mail
Dim mail = New Rebex.Mail.MailMessage()
mail.Load("C:\MyData\TNEF-mail.eml")

' get the HTML equivalent of RTF body
Dim html As String = mail.BodyHtml

' find the original RTF body
Dim rtf As String = Nothing
For Each view As AlternateView In mail.AlternateViews
    If view.ContentType.MediaType = Rebex.Mail.MediaTypeNames.Text.Rtf Then
        rtf = view.ContentString
    End If
Next

RTF to HTML converter #

The MailMessage class contains RTF to HTML convertor, to make displaying emails easier (since HTML is more supported than RTF). The conversion is applied when loading a MailMessage with RTF body (most often when loading MS-TNEF or Outlook MSG messages).

However, you can easily utilize this functionality to convert RTF text to HTML:

CSharp

// create RTF stream
string rtfString = @"{\rtf1\ansi This is \b rich\b0  \i text\i0}";
var rtfStream = new MemoryStream(Encoding.ASCII.GetBytes(rtfString));

// create mail with RTF body
var view = new Rebex.Mail.AlternateView(rtfStream, Rebex.Mail.MediaTypeNames.Text.Rtf);
var mail = new Rebex.Mail.MailMessage();
mail.AlternateViews.Add(view);

// save mail to stream
var stream = new MemoryStream();
mail.Save(stream);

// load mail from stream
stream.Position = 0;
mail.Load(stream);

// get converted HTML text
string html = mail.BodyHtml;

VisualBasic

' create RTF stream
Dim rtfString As String = "{\rtf1\ansi This is \b rich\b0  \i text\i0}"
Dim rtfStream = New MemoryStream(Encoding.ASCII.GetBytes(rtfString))

' create mail with RTF body
Dim view = New Rebex.Mail.AlternateView(rtfStream, Rebex.Mail.MediaTypeNames.Text.Rtf)
Dim mail = New Rebex.Mail.MailMessage()
mail.AlternateViews.Add(view)

' save mail to stream
Dim stream = New MemoryStream()
mail.Save(stream)

' load mail from stream
stream.Position = 0
mail.Load(stream)

' get converted HTML text
Dim html As String = mail.BodyHtml

Message options #

The MailMessage and MimeMessage objects have the Options property, which makes it possible to tweak various behaviors.

The following code only loads the message headers. It is useful, when you have a lot of messages, but you only need to display basic info stored in headers (loading and parsing whole message would be slow).

CSharp

// create mail
var mail = new Rebex.Mail.MailMessage();

// set option to parse only headers
mail.Options = MimeOptions.OnlyParseHeaders;

// load headers of the message
mail.Load(@"C:\MyData\mail.eml");

// print some values stored in headers
Console.WriteLine("Date: {0}", mail.Date);
Console.WriteLine("From: {0}", mail.From);
Console.WriteLine("To: {0}", mail.To);
Console.WriteLine("Subject: {0}", mail.Subject);

VisualBasic

' create mail
Dim mail = New Rebex.Mail.MailMessage()

' set option to parse only headers
mail.Options = MimeOptions.OnlyParseHeaders

' load headers of the message
mail.Load("C:\MyData\mail.eml")

' print some values stored in headers
Console.WriteLine("Date: {0}", mail.Date)
Console.WriteLine("From: {0}", mail.From)
Console.WriteLine("To: {0}", mail.To)
Console.WriteLine("Subject: {0}", mail.Subject)

Low-level MIME API #

Rebex.Mime.MimeMessage class represents a MIME message. It provides a low-level API for manipulating the tree of MIME entities and can be even used to work with MIME entities that don't represent mail messages. It gives you more control, but it's not as simple as MailMessage.

MimeMessage object gives you full control over the MIME entity tree. This can be useful, but it also leads to more complicated code compared to MailMessage object.

The following code generates a simple mail message:

CSharp

// create MIME message
var mime = new Rebex.Mime.MimeMessage();

// fill some fields
mime.From = "joe@example.org";
mime.To = "john@example.org";
mime.Subject = "Test";

// set correct content-type of MIME message
mime.ContentType = new ContentType("multipart/mixed");

// add text and HTML bodies
{
    // create new node for MIME tree
    var bodies = new Rebex.Mime.MimeEntity();

    // set correct content-type for MIME bodies
    bodies.ContentType = new ContentType("multipart/alternative");

    // add text body
    var bodyText = new Rebex.Mime.MimeEntity();
    bodyText.SetContent("This is plain-text body.", Rebex.Mail.MediaTypeNames.Text.Plain);
    bodies.Parts.Add(bodyText);

    // add HTML body
    var bodyHtml = new Rebex.Mime.MimeEntity();
    bodyHtml.SetContent("This is <strong>HTML</strong> body.", Rebex.Mail.MediaTypeNames.Text.Html);
    bodies.Parts.Add(bodyHtml);

    mime.Parts.Add(bodies);
}

// add an attachment
var attachment = new Rebex.Mime.MimeEntity();
attachment.ContentDisposition = new ContentDisposition("attachment");
attachment.SetContentFromFile(@"C:\MyData\file.txt", "file.txt", Rebex.Mail.MediaTypeNames.Text.Plain);
mime.Parts.Add(attachment);

VisualBasic

' create MIME message
Dim mime = New Rebex.Mime.MimeMessage()

' fill some fields
mime.From = "joe@example.org"
mime.To = "john@example.org"
mime.Subject = "Test"

' set correct content-type of MIME message
mime.ContentType = New ContentType("multipart/mixed")

' add text and HTML bodies
If True Then
    ' create new node for MIME tree
    Dim bodies = New Rebex.Mime.MimeEntity()

    ' set correct content-type for MIME bodies
    bodies.ContentType = New ContentType("multipart/alternative")

    ' add text body
    Dim bodyText = New Rebex.Mime.MimeEntity()
    bodyText.SetContent("This is plain-text body.", Rebex.Mail.MediaTypeNames.Text.Plain)
    bodies.Parts.Add(bodyText)

    ' add HTML body
    Dim bodyHtml = New Rebex.Mime.MimeEntity()
    bodyHtml.SetContent("This is <strong>HTML</strong> body.", Rebex.Mail.MediaTypeNames.Text.Html)
    bodies.Parts.Add(bodyHtml)

    mime.Parts.Add(bodies)
End If

' add an attachment
Dim attachment = New Rebex.Mime.MimeEntity()
attachment.ContentDisposition = New ContentDisposition("attachment")
attachment.SetContentFromFile("C:\MyData\file.txt", "file.txt", Rebex.Mail.MediaTypeNames.Text.Plain)
mime.Parts.Add(attachment)

MimeMessage makes it possible to access low-level functionality that is hidden by MailMessage. For example, it can be used to contruct any kind of MIME tree or to add adding custom header to attachments:

CSharp

// create an attachment
var attachment = new Rebex.Mime.MimeEntity();
attachment.ContentDisposition = new ContentDisposition("attachment");
attachment.SetContent(source);

// add custom header to the attachment
attachment.Headers.Add("X-My-Header-Name", "Some value");

VisualBasic

' create an attachment
Dim attachment = New Rebex.Mime.MimeEntity()
attachment.ContentDisposition = New ContentDisposition("attachment")
attachment.SetContent(source)

' add custom header to the attachment
attachment.Headers.Add("X-My-Header-Name", "Some value")

Tip: Unless you need to work directly with the MIME tree and its entities, we strongly recommend using the simpler MailMessage object.

Tip: MimeMessage works with messages stored in the MIME (.eml) format. If you need to process mail messages stored in Microsoft Outlook proprietary format try Rebex.Mail.OutlookMessage class available at labs.rebex.net/OutlookMessage. It provides a simple API for direct manipulating Outlook .msg messages (without internal conversions causing lose of some .msg data).