-
Notifications
You must be signed in to change notification settings - Fork 36
OpaqueMail Library Tutorial
It's easy to get started with the OpaqueMail .NET library.
- Downloading the latest version
- Using the test client
- Sending email with SMTP
- Handling email with IMAP
- Handling email with POP3
- Advanced techniques
The latest release of the OpaqueMail .NET library is always available on GitHub from https://github.com/bertjohnson/OpaqueMail/zipball/master.
The OpaqueMail .NET library is based on Microsoft .NET 4.5.
The OpaqueMail .NET library ships with a fully-featured test client named OpaqueMail.Net.TestClient.exe.
The test client can be used to send test messages with or without S/MIME signing and encryption. These can then be accessed via IMAP and POP3 interfaces, which load messages with all images embedded and scripts removed. The test client supports multiple encodings and character sets.
A. Enter OpaqueMail .NET test client settings
The first step in using the test client is to enter your server settings. By default, SMTP, IMAP, and POP3 settings are listed for Gmail.
If you plan to use the OpaqueMail .NET test client multiple times, you may save and load your server settings using the buttons on the bottom.
B. Load and view IMAP or POP3 messages
Using the "IMAP" or "POP3" tabs, first click "Retrieve Messages". Up to 25 of the most recent messages will load asynchronously.
Once loaded, select a message's title from the lefthand panel. This will load the email's properties and a preview of the message.
C. Send S/MIME signed or encrypted messages via SMTP
Under the SMTP tab, messages can be composed and sent to one or more recipient. Attachments can be specified, the full path of each on its own line.
The OpaqueMail .NET test client supports sending S/MIME signed, encrypted, or triple-wrapped messages if the sender has a valid email certificate (by specifying the hexadecimal serial number). To obtain a certificate, view the tutorial.
The Simple Mail Transfer Protocol (SMTP) is the ubiquitous standard for sending email.
1. Sending a standard email
The OpaqueMail.Net.SmtpClient inherits from the System.Net.Mail.SmtpClient base class. It adds multiple properties and methods for working with S/MIME messages.
If sending a standard, unsigned and unencrypted message, either of the System.Net.Mail.SmtpClient or OpaqueMail.Net.SmtpClient classes can be used with the Send() or SendAsync() methods. As you'll see in upcoming examples, differences only emerge when working with S/MIME messages.
// Instantiate a new SMTP connection to Gmail using TLS/SSL protection.
SmtpClient smtpClient = new SmtpClient("smtp.gmail.com", 587);
smtpClient.Credentials = new NetworkCredential("[email protected]", "Pass@word1");
smtpClient.EnableSsl = true;
// Create a new MailMessage class with lorem ipsum.
MailMessage message = new MailMessage("[email protected]", "[email protected]", "Example subject", "Lorem ipsum body.");
// Send the message asynchronously.
await smtpClient.SendAsync(message);
2. Sending an S/MIME signed email
Sending an S/MIME signed message is very similar to sending a standard email message using the SmtpClient class.
To specify that the message should be signed, first set the SmimeSigned property to true. You can then (optionally) choose signing options such as whether the signature should be timestamped using the Timestamp Protocol (TSP).
Finally, an S/MIME signing certificate needs to be assigned. This can be simplified using the CertHelper class's GetCertificateBySerialNumber or GetCertificateBySubjectName methods.
// Instantiate a new SMTP connection to Gmail using TLS/SSL protection.
SmtpClient smtpClient = new SmtpClient("smtp.gmail.com", 587);
smtpClient.Credentials = new NetworkCredential("[email protected]", "Pass@word1");
smtpClient.EnableSsl = true;
// Create a new MailMessage class with lorem ipsum.
MailMessage message = new MailMessage("[email protected]", "[email protected]", "Example subject", "Lorem ipsum body.");
// Specify that the message should be S/MIME signed, including its timestamp.
message.SmimeSigned = true;
message.SmimeSigningOptionFlags = SmimeSigningOptionFlags.SignTime;
// Load the signing certificate from the Local Machine store.
message.SmimeSigningCertificate = CertHelper.GetCertificateBySubjectName(StoreLocation.LocalMachine, "[email protected]");
// Send the message.
await smtpClient.SendAsync(message);
3. Sending an S/MIME encrypted email
Sending an S/MIME message with its envelope encrypted resembles sending a signed message using the SmtpClient class.
To specify that the message's envelope should be encrypted, simply set the SmimeEncryptedEnvelope property to true, then use Send() or SendAsync() as normal.
// Instantiate a new SMTP connection to Gmail using TLS/SSL protection.
SmtpClient smtpClient = new SmtpClient("smtp.gmail.com", 587);
smtpClient.Credentials = new NetworkCredential("[email protected]", "Pass@word1");
smtpClient.EnableSsl = true;
// Create a new MailMessage class with lorem ipsum.
MailMessage message = new MailMessage("[email protected]", "[email protected]", "Example subject", "Lorem ipsum body.");
// Specify that the message's envelope should be S/MIME encrypted.
message.SmimeEncryptedEnvelope = true;
// Send the message.
await smtpClient.SendAsync(message);
4. Sending an S/MIME triple-wrapped email
Triple-wrapped messages provide additional safeguards over simply encrypted S/MIME messages. To triple wrap a message, it is first signed, then that signed message is encrypted, and finally that encrypted portion is again signed. This provides additional assurance regarding the message's origin and that it has not been tampered with.
Sending a triple-wrapped S/MIME message combines the steps of signing and encrypting a message using the SmtpClient class. In addition to setting the SmimeSigned and SmimeEncryptedEnvelope properties to true, the SmimeTripleWrapped property needs to be true.
// Instantiate a new SMTP connection to Gmail using TLS/SSL protection.
SmtpClient smtpClient = new SmtpClient("smtp.gmail.com", 587);
smtpClient.Credentials = new NetworkCredential("[email protected]", "Pass@word1");
smtpClient.EnableSsl = true;
// Create a new MailMessage class with lorem ipsum.
MailMessage message = new MailMessage("[email protected]", "[email protected]", "Example subject", "Lorem ipsum body.");
// Specify that the message should be signed, have its envelope encrypted, and then be signed again (triple-wrapped).
message.SmimeSigned = true;
message.SmimeEncryptedEnvelope = true;
message.SmimeTripleWrapped = true;
// Specify that the message should be timestamped.
message.SmimeSigningOptionFlags = SmimeSigningOptionFlags.SignTime;
// Load the signing certificate from the Local Machine store.
message.SmimeSigningCertificate = CertHelper.GetCertificateBySubjectName(StoreLocation.LocalMachine, "[email protected]");
// Send the message.
await smtpClient.SendAsync(message);
Internet Message Access Protocol (IMAP) is a common option for email query and retrieval. It offers more capabilities than POP3 and continues to evolve. IMAP is supported by most enterprise hosts.
1. Connecting to an IMAP server
Connecting to an IMAP server with the OpaqueMail .NET library requires only a few steps. It requires instantiating an ImapClient class, calling the Connect() method, and calling the Authenticate() method.
// Instantiate a new IMAP connection to Gmail using TLS/SSL protection.
ImapClient imapClient = new ImapClient("imap.gmail.com", 993, "[email protected]", "Pass@word1", true);
imapClient.Connect();
imapClient.Authenticate();
2. Retrieving a list of IMAP messages
IMAP messages can be retrieved in bulk using the ImapClient class. The GetMessages() and GetMessagesAsync() methods are overloaded with multiple options to retrieve a certain number of messages, in either ascending or descending order, with either headers only or entire messages.
// Instantiate a new IMAP connection to Gmail using TLS/SSL protection.
ImapClient imapClient = new ImapClient("imap.gmail.com", 993, "[email protected]", "Pass@word1", true);
imapClient.Connect();
imapClient.Authenticate();
// Retrieve up to 50 of the most recent messages from the "Inbox" mailbox.
List<MailMessage> recentMessages = imapClient.GetMessages("Inbox", 50);
// Retrieve up to 10 of the most recent messages from the "Inbox" mailbox asynchronously, with headers only.
List<MailMessage> messagesWithHeadersOnly = await imapClient.GetMessagesAsync("Inbox", 10, true);
// Retrieve up to 25 messages from the "Drafts" mailbox in reverse order, not setting the "Seen" flag.
List<MailMessage> messagesInReverse = imapClient.GetMessages("Drafts", 25, 0, true, false, false);
3. Downloading a specific IMAP message
IMAP messages can be downloaded individually using the ImapClient class.
The GetMessage() and GetMessageAsync() methods are overloaded with multiple options to retrieve a certain message by its index on the server. The GetMessageUid() and GetMessageUidAsync() methods do the same based on a message's Unique ID (UID). A boolean determines whether the entire message is returned or only its headers.
// Instantiate a new IMAP connection to Gmail using TLS/SSL protection.
ImapClient imapClient = new ImapClient("imap.gmail.com", 993, "[email protected]", "Pass@word1", true);
imapClient.Connect();
imapClient.Authenticate();
// Retrieve the 5th most recent message.
MailMessage fifthIndexMessage = imapClient.GetMessage(5);
// Retrieve the most recent message asynchronously, with headers only.
MailMessage messageHeadersOnly = await imapClient.GetMessageAsync("Inbox", 1, true);
// Retrieve the message with UID 57.
MailMessage uidlMessage = imapClient.GetMessageUid(57);
4. Searching IMAP messages
Similar to simply retrieving messages using the GetMessages() and GetMessagesAsync() methods, the ImapClient class offers the Search() and SearchAsync() methods for querying and retrieving messages.
Queries are defined directly as well-formatted strings in accordance with the IMAP standard.
// Instantiate a new IMAP connection to Gmail using TLS/SSL protection.
ImapClient imapClient = new ImapClient("imap.gmail.com", 993, "[email protected]", "Pass@word1", true);
imapClient.Connect();
imapClient.Authenticate();
// Search the headers and body of each message asynchronously for the string "opaque".
List<MailMessage> searchOpaqueMessages = await imapClient.SearchAsync("TEXT \"opaque\"");
// Search each message for a sender with the word "Bert".
List<MailMessage> searchBertMessages = imapClient.Search("FROM \"Bert\"");
5. Deleting IMAP messages
IMAP messages can be deleted individually or as an array using the ImapClient class.
The DeleteMessage(), DeleteMessageAsync(), DeleteMessages(), and DeleteMessagesAsync() delete one or more messages identified by index. The DeleteMessageUid(), DeleteMessageUidAsync(), DeleteMessagesUid(), and DeleteMessagesUidAsync() delete one or more messages identified by UID.
// Instantiate a new IMAP connection to Gmail using TLS/SSL protection.
ImapClient imapClient = new ImapClient("imap.gmail.com", 993, "[email protected]", "Pass@word1", true);
imapClient.Connect();
imapClient.Authenticate();
// Delete the 7th most recent message from the Inbox mailbox.
imapClient.DeleteMessage("Inbox", 7);
// Delete the most recent message asynchronously.
await imapClient.DeleteMessageAsync("Inbox", 1);
// Delete the message with UID 215.
imapClient.DeleteMessageUid("Inbox", 215);
// Delete the 2nd, 3rd, and 5th most recent messages in the Drafts mailbox.
imapClient.DeleteMessages("Drafts", new int[] { 2, 3, 5 });
6. Getting a list of IMAP capabilities
IMAP has evolved substantially and server implementations have widely varying capabilities. Built-in OpaqueMail .NET library functions check for server capabilities before using them. For example, the library checks if the server supports the "Move" command before moving messages. If so, it uses that; otherwise, it first copies the message then deletes the original.
Sometimes, it may be useful to check a server's capability directly. This can be done through the ImapClient class's GetCapabilities() method, which returns a string array of server capabilities. Alternatively, there are several properties that start with Supports* (such as SupportsIdle) to check a specific capability directly.
These capabilities are calculated upon logging into the IMAP server, so there are no roundtrips needed to verify a capability.
// Instantiate a new IMAP connection to Gmail using TLS/SSL protection.
ImapClient imapClient = new ImapClient("imap.gmail.com", 993, "[email protected]", "Pass@word1", true);
imapClient.Connect();
imapClient.Authenticate();
// Get and output the IMAP server version and list of capabilities.
string imapVersion;
string[] capabilities = imapClient.GetCapabilities(out imapVersion);
Console.WriteLine("IMAP Server Version: " + imapVersion);
int capabilityIndex = 0;
foreach (string capability in capabilities)
Console.WriteLine("Capability #" + (++capabilityIndex) + ": " + capability);
// Alternatively, check for specific capabilities.
Console.WriteLine("Supports Idle: " + imapClient.SupportsIdle);
Console.WriteLine("Supports Multi-Append: " + imapClient.SupportsMultiAppend);
Console.WriteLine("Supports UID+: " + imapClient.SupportsUIDPlus);
7. Appending IMAP messages
The OpaqueMail .NET library's ImapClient class supports individual message appending through AppendMessage() and AppendMessageAsync, as well as batch message appending with AppendMessages() and AppendMessagesAsync().
When using AppendMessages() or AppendMessagesAsync(), the client first checks to see if the server supports IMAP's "MULTIAPPEND" extension, and uses that if so. If not, each message is appended individually.
// Instantiate a new IMAP connection to Gmail using TLS/SSL protection.
ImapClient imapClient = new ImapClient("imap.gmail.com", 993, "[email protected]", "Pass@word1", true);
imapClient.Connect();
imapClient.Authenticate();
// Append an individual message.
imapClient.AppendMessage("INBOX",
@"Date: " + DateTime.Now.ToString("dd-MM-yyyy hh:mm:ss zzzz") + @"
From: Test User <[email protected]>
To: Me <[email protected]>
Message-Id: <" + Guid.NewGuid().ToString().Replace("{", "").Replace("}", "") + @"@gmail.com>
Subject: Test Append Message
MIME-Version: 1.0
Content-Type: Text/Plain; Charset=US-ASCII
This is a test of the APPEND command.", new string[] { @"\Seen" }, DateTime.Now);
// Append multiple message.
await imapClient.AppendMessagesAsync("INBOX", messageArray);
8. Copying IMAP messages
Messages can be copied between IMAP mailboxes using the ImapClient's CopyMessage(), CopyMessageAsync(), CopyMessageUid(), and CopyMessageUidAsync() methods.
// Instantiate a new IMAP connection to Gmail using TLS/SSL protection.
ImapClient imapClient = new ImapClient("imap.gmail.com", 993, "[email protected]", "Pass@word1", true);
imapClient.Connect();
imapClient.Authenticate();
// Copy the 2nd message in the "Inbox" mailbox to the user's "Memories" mailbox asynchronously.
await imapClient.CopyMessageAsync("Inbox", 2, "Memories");
// Copy the message with UID "410" from the "Inbox" mailbox to the "Junk" mailbox.
imapClient.CopyMessageUid("Inbox", 410, "Junk");
9. Working with IMAP mailboxes
The OpaqueMail .NET library's ImapClient class supports numerous options for working with mailboxes.
Mailboxes can be selected with the SelectMailbox() and SelectMailboxAsync() methods. Certain methods that accept "mailboxName" as a parameter (such as GetMessage()) automatically perform a SelectMailbox() or SelectMailboxAsync() when needed.
Mailboxes can be deployed with the CreateMailbox() and CreateMailboxAsync() methods. Mailboxes can then be deleted using DeleteMailbox() and DeleteMailboxAsync(). Messages marked for deletion can be discarded using the ExpungeMailbox() and ExpungeMailboxAsync() methods.
ListMailboxes() and ListMailboxesAsync() return arrays of Mailbox objects with information about each whereas ListMailboxNames() and ListMailboxNamesAsync() return arrays of the mailbox names only.
If the extension is available, OpaqueMail uses the "XLIST" verb. ExamineMailbox() and ExamineMailboxAsync() return information about a particular mailbox via a Mailbox object, such as its size and number of messages.
// Instantiate a new IMAP connection to Gmail using TLS/SSL protection.
ImapClient imapClient = new ImapClient("imap.gmail.com", 993, "[email protected]", "Pass@word1", true);
imapClient.Connect();
imapClient.Authenticate();
// Retrieve and print the list of all mailboxes, including the full hierarchy.
string[] mailboxNames = imapClient.ListMailboxNames(true);
int mailboxId = 0;
foreach (string mailboxName in mailboxNames)
Console.WriteLine("Mailbox #" + (++mailboxId) + ": " + mailboxName);
// Select the "Drafts" mailbox asynchronously, ensuring subsequent commands take place within it.
await imapClient.SelectMailboxAsync("Drafts");
// Examine the "Important" mailbox and output some of its properties.
Mailbox importantMailbox = imapClient.ExamineMailbox("Important");
Console.WriteLine("Mailbox message count: " + importantMailbox.Count);
Console.WriteLine("Mailbox recent message count: " + importantMailbox.Recent);
Console.WriteLine("Mailbox next UID: " + importantMailbox.UidNext);
// Asyncrhonously delete the "Unused" mailbox.
await imapClient.DeleteMailboxAsync("Unused");
10. Working with IMAP subscriptions
The OpaqueMail .NET library supports ImapClient mailbox subscriptions through several commands.
The ListSubscriptions() and ListSubscriptionsAsync() methods return arrays of Mailbox objects, whereas the ListSubscriptionNames() and ListSubscriptionNamesAsync() methods return array of the mailbox names only.
Subscriptions can be created through the SubscribeMailbox(), SubscribeMailboxAsync(), UnsubscribeMailbox(), and UnsubscribeMailboxAsync() methods.
// Instantiate a new IMAP connection to Gmail using TLS/SSL protection.
ImapClient imapClient = new ImapClient("imap.gmail.com", 993, "[email protected]", "Pass@word1", true);
imapClient.Connect();
imapClient.Authenticate();
// Retrieve and print the list of all subscriptions, including the full hierarchy.
string[] mailboxNames = imapClient.ListSubscriptionNames(true);
int mailboxId = 0;
foreach (string mailboxName in mailboxNames)
Console.WriteLine("Mailbox #" + (++mailboxId) + ": " + mailboxName);
// Create a new subscription for the "Announcements" mailbox asynchronously.
await imapClient.SubscribeMailboxAsync("Announcements");
11. Working with IMAP quotas
The OpaqueMail .NET library enabled getting and settings quotas on supported IMAP servers. To check if the server supports quota commands, the ">ImapClient's SupportsQuota property can be checked.
If supported, the methods GetQuota(), GetQuotaAsync(), GetQuotaRoot(), GetQuotaRootAsync(), SetQuota(), and SetQuotaRoot() can be used, which interact with QuotaUsage objects.
// Confirm the server supports quota commands.
if (imapClient.SupportsQuota)
{
// Determine and output the root quota usage.
QuotaUsage quotaRoot = imapClient.GetQuotaRoot("Inbox");
Console.WriteLine("Quota usage for Inbox: " + quotaRoot.Usage + " out of " + quotaRoot.QuotaMaximum);
// Asynchronously set the "Memories" mailbox to have a quota of 1 GB (1024 MB).
await imapClient.SetQuotaAsync("Memories", 1024);
}
12. Encrypting IMAP with STARTTLS and compressing IMAP with DEFLATE
IMAP traffic can be protected by TLS/SSL encryption either upon connecting to the remote server or after issuing the "STARTTLS" command. The ">ImapClient's StartTLS() method performs a TLS handshake and replaces the underlying NetworkStream objects with SslStream equivalents.
If a server supports the "DEFLATE" compression algorithm, the StartDeflateCompression() can be used to minimize bandwidth. If the server doesn't support that algorithm, the session continues as normal.
// Instantiate a new IMAP connection to Gmail using TLS/SSL protection.
ImapClient imapClient = new ImapClient("imap.gmail.com", 993, "[email protected]", "Pass@word1", true);
imapClient.Connect();
// Now that we're connected, start TLS protection.
imapClient.StartTLS();
// Authenticate.
imapClient.Authenticate();
// If the remote server supports it, negotate DEFLATE compression.
imapClient.StartDeflateCompression();
13. Keeping IMAP connections alive
There are multiple ways to keep an IMAP connection alive in order to be notified of server events (such as new messages). One of the most basic ways is to issue a command on a regular basis in order to prevent the session from timing out. The OpaqueMail .NET library's ">ImapClient can issue NoOp() commands to do so.
Some servers also support the "Idle" command set. A client can start "idling" by calling the IdleStart() or IdleStartAsync() methods. When idling, a timer runs on a regular basis (by default, every minute) to check for and process new messages from the server. When ready to issue other commands, the client should then run the IdleStop() or IdleStopAsync() which stops the timer.
"Idling" is useful when paired with IMAP events.
You can check if an ImapClient is currently "idling" and running a command processing timer by accessing its IsIdle property.
// Instantiate a new IMAP connection to Gmail using TLS/SSL protection.
ImapClient imapClient = new ImapClient("imap.gmail.com", 993, "[email protected]", "Pass@word1", true);
imapClient.Connect();
imapClient.Authenticate();
// Check how many messages there currently are.
int messageCount = await imapClient.GetMessageCountAsync();
Console.WriteLine("There are currently " + messageCount + " messages>");
// Sleep for 20 minutes, but process messages while idle.
imapClient.IdleStart();
System.Threading.Thread.Sleep(new TimeSpan(0, 20, 0));
imapClient.IdleStop();
14. Handling IMAP events
The OpaqueMail .NET ImapClient class supports four events that can be responded to using .NET's eventing model.
If the client is unexpectedly disconnected from the server, the ImapClientDisconnectEvent is fired.
If the IMAP connection speed is throttled by the remote server, the ImapClientThrottleEvent is fired. Whenever a new message notification is received, the ImapClientNewMessageEvent is fired.
Whenever a message expunge notification is received, the ImapClientMessageExpungeEvent is fired.
// Whenever a message is expunged, show an alert.
private void imapClient_ImapClientMessageExpungeEvent(object sender, ImapClientEventArgs e)
{
MessageBox.Show("Message expunged.\r\n\r\nMailbox: " + e.MailboxName + "\r\nMessage ID: " + e.MessageId, "Message expunged.", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
// Whenever a new message arrives, show an alert.
private void imapClient_ImapClientNewMessageEvent(object sender, ImapClientEventArgs e)
{
MessageBox.Show("New message received.\r\n\r\nMailbox: " + e.MailboxName + "\r\nMessage ID: " + e.MessageId, "New message received", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private async void Main()
{
// Instantiate a new IMAP connection to Gmail using TLS/SSL protection.
ImapClient imapClient = new ImapClient("imap.gmail.com", 993, "[email protected]", "Pass@word1", true);
imapClient.Connect();
imapClient.Authenticate();
// Create event handler for new messages and expunged messages.
imapClient.ImapClientNewMessageEvent += imapClient_ImapClientNewMessageEvent;
imapClient.ImapClientMessageExpungeEvent += imapClient_ImapClientMessageExpungeEvent;
await myImapClient.IdleStartAsync();
}
The Post Office Protocol version 3 (POP3) is the simplest mechanism for retrieving email. It doesn't feature as much functionality as IMAP, but it's supported by the vast majority of email hosts.
1. Connecting to a POP3 server
Connecting to a POP3 server with OpaqueMail is straightforward. It only requires instantiating a Pop3Client, calling the Connect() method, and optionally calling the Authenticate() method. Some POP3 servers are anonymous, and thus don't need the Authenticate() call.
// Instantiate a new POP3 connection to Gmail using TLS/SSL protection.
Pop3Client pop3Client = new Pop3Client("pop.gmail.com", 995, "[email protected]", "Pass@word1", true);
pop3Client.Connect();
pop3Client.Authenticate();
2. Retrieving a list of POP3 messages
POP3 messages can be retrieved in bulk using the Pop3Client class. The GetMessages() and GetMessagesAsync() methods are overloaded with multiple options to retrieve a certain number of messages, in either ascending or descending order, with either headers only or entire messages.
// Instantiate a new POP3 connection to Gmail using TLS/SSL protection.
Pop3Client pop3Client = new Pop3Client("pop.gmail.com", 995, "[email protected]", "Pass@word1", true);
pop3Client.Connect();
pop3Client.Authenticate();
// Retrieve up to 50 of the most recent messages.
List<MailMessage> recentMessages = pop3Client.GetMessages(50);
// Retrieve up to 10 of the most recent messages asynchronously, with headers only.
List<MailMessage> messagesWithHeadersOnly = await pop3Client.GetMessagesAsync(10, true);
// Retrieve up to 25 messages in reverse order.
List<MailMessage> messagesInReverse = pop3Client.GetMessages(25, 0, true);
3. Downloading a specific POP3 message
POP3 messages can be downloaded individually using the Pop3Client class.
The GetMessage() and GetMessageAsync() methods are overloaded with multiple options to retrieve a certain message by its index on the server. The GetMessageUid() and GetMessageUidAsync() methods do the same based on a message's UID as returned by the UIDL command. A boolean determines whether the entire message is returned or only its headers.
// Instantiate a new POP3 connection to Gmail using TLS/SSL protection.
Pop3Client pop3Client = new Pop3Client("pop.gmail.com", 995, "[email protected]", "Pass@word1", true);
pop3Client.Connect();
pop3Client.Authenticate();
// Retrieve the 5th most recent message.
MailMessage fifthIndexMessage = pop3Client.GetMessage(5);
// Retrieve the most recent message asynchronously, with headers only.
MailMessage messageHeadersOnly = await pop3Client.GetMessageAsync(1, true);
// Retrieve the message with UID "whqtswO00WBw418f9t5JxYwZ" as returned by the UIDL command.
MailMessage uidlMessage = pop3Client.GetMessageUid("whqtswO00WBw418f9t5JxYwZ");
4. Deleting POP3 messages
POP3 messages can be deleted individually or as an array using the Pop3Client class.
The DeleteMessage(), DeleteMessageAsync(), DeleteMessages(), and DeleteMessagesAsync() delete one or more messages identified by index. The DeleteMessageUid(), DeleteMessageUidAsync(), DeleteMessagesUid(), and DeleteMessagesUidAsync() delete one or more messages identified by UID.
// Instantiate a new POP3 connection to Gmail using TLS/SSL protection.
Pop3Client pop3Client = new Pop3Client("pop.gmail.com", 995, "[email protected]", "Pass@word1", true);
pop3Client.Connect();
pop3Client.Authenticate();
// Delete the 7th most recent message.
pop3Client.DeleteMessage(7);
// Delete the most recent message asynchronously.
await pop3Client.DeleteMessageAsync(7);
// Delete the message with UID "whqtswO00WBw418f9t5JxYwZ".
pop3Client.DeleteMessageUid("whqtswO00WBw418f9t5JxYwZ");
// Delete the 2nd, 3rd, and 5th most recent messages.
pop3Client.DeleteMessages(new int[] { 2, 3, 5 });
5. Getting a list of POP3 capabilities
Modern POP3 servers advertise their extensions via the "CAPA" command, which can be queried from the Pop3Client class.
The GetCapabilities() and GetCapabilitiesAsync() methods return a string array of reported capabilities.
// Instantiate a new POP3 connection to Gmail using TLS/SSL protection.
Pop3Client pop3Client = new Pop3Client("pop.gmail.com", 995, "[email protected]", "Pass@word1", true);
pop3Client.Connect();
pop3Client.Authenticate();
// Get a list of capabilities, then loop through and print them out.
string[] capabilities = await pop3Client.GetCapabilitiesAsync();
foreach (string capability in capabilities)
Console.WriteLine("Capability reported: " + capability);
The following topics are more advanced. Message processing applies equally whether working with IMAP or POP3.
##1. Determining whether a message was S/MIME signed or encrypted##
The OpaqueMail .NET library processes S/MIME messages automatically. Regardless of whether a message was signed, encrypted, or triple-wrapped, the MailMessage class will attempt to decrypt and extract the message contained within.
The MailMessage class can be interrogated to check whether S/MIME operations were performed. If it was signed, the SmimeSigningCertificateChain will be populated.
// Instantiate a new POP3 connection to Gmail using TLS/SSL protection.
Pop3Client pop3Client = new Pop3Client("pop.gmail.com", 995, "[email protected]", "Pass@word1", true);
pop3Client.Connect();
pop3Client.Authenticate();
// Retrieve the most recent message.
MailMessage mostRecentMessage = pop3Client.GetMessage(1);
// Output information about S/MIME operations performed on the message.
Console.WriteLine("S/MIME Signed?: " + mostRecentMessage.SmimeSigned);
if (mostRecentMessage.SmimeSigned)
{
// If the most recent message was signed, output its signing certificate chain.
int certIndex = 0;
foreach (X509Certificate2 cert in mostRecentMessage.SmimeSigningCertificateChain)
Console.WriteLine("S/MIME Certificate #" + (++certIndex) + ": " + cert.Subject);
}
Console.WriteLine("S/MIME Encrypted Envelope?: " + mostRecentMessage.SmimeEncryptedEnvelope);
Console.WriteLine("S/MIME Triple-Wrapped?: " + mostRecentMessage.SmimeTripleWrapped);
2. Processing TNEF-encoded messages
Transport-Neutral Encapsulation Format (TNEF) is a proprietary encoding format created by Microsoft. It was common with early versions of Outlook and Outlook Express and had a reputation for combining email attachments into a file called "winmail.dat".
While not as common as it used to be, TNEF-encoded messages are still transmitted. The OpaqueMail .NET library automatically parses TNEF-encoded messages and extracts their attachments.
If you'd like to manually decode a TNEF-encoded message using the OpaqueMail .NET library, you can do so with the following code.
// Instantiate a TNEF Encoding object to process the byte array "tnefEncoddedBytes".
TnefEncoding tnefEncoding = new TnefEncoding(tnefEncodedBytes);
// Loop through the TNEF-encoded attachments, outputting their names, content types, and sizes.
foreach (MimePart mimePart in tnefEncoding.MimeAttachments)
{
Console.WriteLine("MIME Part Name: " + mimePart.Name);
Console.WriteLine("MIME Part Content Type: " + mimePart.ContentType);
Console.WriteLine("MIME Part Size: " + mimePart.BodyBytes.Length);
}
3. Loading a message from a .eml file
The OpaqueMail .NET library can load email messages directly from plaintext .eml and .msg files. To do so, use the MailMessage's static LoadFile() method to hydrate a new object. The following example uses the Functions helper class's ToMailAddressString helper method, which accepts a MailAddress or MailAddress collection and returns a readable string.
// Load a message from its .eml file representation, then output its subject, sender, and recipients.
MailMessage loadedMessage = MailMessage.LoadFile("C:\\message.eml");
Console.WriteLine("Message Subject: " + loadedMessage.Subject);
Console.WriteLine("Message Sender: " + Functions.ToMailAddressString(loadedMessage.From));
Console.WriteLine("Message Recipients: " + Functions.ToMailAddressString(loadedMessage.To));
4. Removing <Script/> tags from a message
The OpaqueMail .NET library includes several helper functions that tackle common email tasks. Javascript code easily can be stripped from a message by calling RemoveScriptTags() from the Functions helper class. In addition to removing <Script/> blocks, embedded event handlers like onclick will be removed.
// Load a message from its .eml file representation.
MailMessage loadedMessage = MailMessage.LoadFile("C:\\message.eml");
// Strip Javascript from the message's body prior to rendering it.
string scrubbedBodyToDisplay = Functions.RemoveScriptTags(loadedMessage.Body);
5. Embedding attachments inline
One of the helper functions in OpaqueMail .NET's Functions helper class is EmbedAttachments(). This method will take a MIME attachment collection and replace any CID: attachment references in the body with their Base-64 encoded bytes. This is a common requirement for text/html emails.
// Load a message from its .eml file representation.
MailMessage loadedMessage = MailMessage.LoadFile("C:\\message.eml");
// Load a web browser control and load it with the message's body, with attachments embedded.
WebBrowser browser = new WebBrowser();
browser.DocumentText = Functions.EmbedAttachments(message.Body, message.Attachments);
6. Manually encoding or decoding text
The OpaqueMail .NET library automatically handles message encoding/decoding automatically converts character sets (e.g. between Unicode and UTF-8). It was designed with internationalization (i18n) and localization in mind.
Its Functions helper class exposes several encoding and decoding functions that may be useful.
// Attempt to convert a text/plain body to text/html.
Functions.ConvertPlainTextToHTML("This is a test link to http://opaquemail.org/");
// The example above outputs "This is a test link to <a href="http://opaquemail.org/">http://opaquemail.org/</a>".
// Escape Base-64 and quoted-printable encodings in message headers, as indicated by ?B? or ?Q?.
string decodedMailHeader = Functions.DecodeMailHeader(mailHeader);
// Encode a mail header, choosing the proper encoding.
string encodedMailHeader = Functions.EncodeMailHeader(mailHeader);
// Decode a Base-64 encoded message.
string decodedString = Functions.FromBase64(base64EncodedString);
// Decode a Modified UTF-7 string, as used for IMAP mailbox names.
string decodedMailBoxName = Functions.FromModifiedUTF7(mailBoxName);
// Decode a quoted-printable message.
decodedString = Functions.FromQuotedPrintable(quotedPrintableEncodedString);
// Span a mail header over multiple lines of 70 characters or fewer, per SMTP guidelines.
string spannedMailHeader = Functions.SpanHeaderLines(mailHeader);
// Encode a message in Base-64.
Functions.ToBase64String(decodedString);
// Encode a string as Modified UTF-7, as used for IMAP mailbox names.
string encodedMailboxName = Functions.ToModifiedUTF7(mailBoxName);
// Decode a UUEncoded string.
Functions.UUDecode(uuEncodedString);
// UUEncode a message.
Functions.UUEncode(unencodedString);