dcsimg

WEBINAR:
On-Demand

Virtual Developer Workshop: Containerized Development with Docker


Outlook's default file format when saving an e-mail to disk is MSG (.msg). Meanwhile, Microsoft Outlook Express and some other e-mail programs, such as Mozilla Thunderbird, save their files in the EML (.eml) format, which follows the MIME RFC 822 standard. Recent versions of Outlook can open EML files, but if you're looking to work with them within Outlook, you'll have to put in a bit of work. In today's article, we'll write some C# code that uses the .NET SmtpClient class to programmatically save e-mails in the EML format.

Saving an E-mail

There are several ways to save an e-mail in EML format, but one of the simplest that I have come across comes from the Stackoverflow site. It sets the SmtpClient's DeliveryMethod to a specified directory. It just happens that the SmtpClient saves e-mails in EML format.

Here's the start of the Program.cs file, which is part of a C# .NET console application:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Mail;
using System.IO;
using System.Reflection;

namespace MailTests
{
   static class Program
   {
      static void Main(string[] args)
      {
         string to       = @"rob@robgravelle.com";
         string from     = @"bifft@gmail.com";
         string subject  = @"Working with the .eml file type in
                             C#.";
         string body     = @"Using the SmtpClient class, you can
                             save an e-mail message in .eml format
                             very easily.";
         string emailDir = @"I:\\My Documents\\articles\\codeguru
                             \\C#\\Saving an E-mail\\SavedMail";
         string msgName  = @"msg.eml";

         Console.WriteLine("Saving e-mail...");
      }
   }
}

Saving the E-mail

The demo app just creates the test e-mail programmatically using our constants above. UseDefaultCredentials is set to true so that we don't have to provide any credentials. Then, the DeliveryMethod is set to use the specified pickup directory. Mail messages in the pickup directory are automatically sent by a local SMTP server (if present), such as IIS. The directory is set in the following line where the PickupDirectoryLocation is set to the emailDir constant.

The Send() invocation is enclosed within a try/catch block because it could fail under certain circumstances, such as not having write permissions on the directory, etcetera. The Console.ReadLine() call waits for user input so that the console doesn't immediately close.

Console.WriteLine("Saving e-mail...");
using (var client = new SmtpClient())
{
   MailMessage msg = new MailMessage(from, to, subject, body);
   client.UseDefaultCredentials = true;
   client.DeliveryMethod =
      SmtpDeliveryMethod.SpecifiedPickupDirectory;
   client.PickupDirectoryLocation = emailDir;
   try
   {
      client.Send(msg);
   }
   catch (Exception ex)
   {
      Console.WriteLine("Exception caught: {0}", ex.ToString());
         Console.ReadLine();
      System.Environment.Exit(-1);
   }
}

Setting the File Name

The SmtpClient saves the file with a random file name comprised of a random Guid, courtesy of Guid.NewGuid(), plus the ".eml" extension, something like "263cf925-aa20-40b4-a860-f03c8ceb9537.eml". This guarantees a unique name, but if you would like something a little more descriptive, there are ways to rename the file. Or if you're really ambitious, use Reflection to construct your own internal MailWriter. The Stackoverflow solution on which my code is based employed Guid.NewGuid() to create a temp directory. This strategy avoids the possibility of overwriting another file with the same name—at least until you move the file to its final destination!

My solution deals with that problem by asking the user to make a decision. The drawback to this approach is that it does not lend itself to unsupervised batch jobs. Without using a temp folder, you also need to be able to identify the new file. I did that by sorting files by LastWriteTime in descending order, so that the new file would be at the top (i.e. first).

var defaultMsgPath = new DirectoryInfo(emailDir).GetFiles()
      .OrderByDescending(f => f.LastWriteTime)
      .First();
var realMsgPath = Path.Combine(emailDir, msgName);
try
{
   File.Move(defaultMsgPath.FullName, realMsgPath);
   Console.WriteLine("Message saved.");
}
catch (System.IO.IOException e)
{
   Console.WriteLine("File already exists. Overwrite it? Y/N");

   var test = Console.ReadLine();
   if (test == "y" || test == "Y")
   {
      Console.WriteLine("Overwriting existing file...");
      File.Delete(realMsgPath);
      File.Move(defaultMsgPath.FullName, realMsgPath);
      Console.WriteLine("Message saved.");
   }
   else
   {
      Console.WriteLine("Exiting Program without saving file.");
   }
}
Console.WriteLine("Press any key to exit.");
Console.ReadLine();

Here is the entire Program.cs file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Mail;
using System.IO;
using System.Reflection;

namespace MailTests
{
   static class Program
   {
      static void Main(string[] args)
      {
         string to       = @"rob@robgravelle.com";
         string from     = @"bifft@gmail.com";
         string subject  = @"Working with the .eml file type in
                             C#.";
         string body     = @"Using the SmtpClient class, you can
                             save an e-mail message in .eml format
                             very easily.";
         string emailDir = @"I:\\My Documents\\articles\\codeguru
                             \\C#\\Saving an E-mail\\SavedMail";
         string msgName  = @"msg.eml";

         Console.WriteLine("Saving e-mail...");
         using (var client = new SmtpClient())
         {
            MailMessage msg = new MailMessage(from, to, subject,
               body);
            client.UseDefaultCredentials = true;
            client.DeliveryMethod =
               SmtpDeliveryMethod.SpecifiedPickupDirectory;
            client.PickupDirectoryLocation = emailDir;
            try
            {
               client.Send(msg);
            }
            catch (Exception ex)
            {
               Console.WriteLine("Exception caught: {0}",
                  ex.ToString());
               Console.ReadLine();
               System.Environment.Exit(-1);
            }
         }

         var defaultMsgPath = new
            DirectoryInfo(emailDir).GetFiles()
               .OrderByDescending(f => f.LastWriteTime)
               .First();
         var realMsgPath = Path.Combine(emailDir, msgName);
         try
         {
            File.Move(defaultMsgPath.FullName, realMsgPath);
            Console.WriteLine("Message saved.");
         }
         catch (System.IO.IOException e)
         {
            Console.WriteLine("File already exists. Overwrite
               it? Y/N");

            var test = Console.ReadLine();
            if (test == "y" || test == "Y")
            {
               Console.WriteLine("Overwriting existing file...");
               File.Delete(realMsgPath);
               File.Move(defaultMsgPath.FullName, realMsgPath);
               Console.WriteLine("Message saved.");
            }
            else
            {
               Console.WriteLine("Exiting Program without saving
                  file.");
            }
         }
         Console.WriteLine("Press any key to exit.");
         Console.ReadLine();
      }
  }
}

Conclusion

As we saw here today, saving a MailMessage as an EML file by using the .NET SmtpClient class is relatively straightforward. That being said, an Outlook MailItem and .NET Framework MailMessage are very different things. In upcoming articles, we'll see how to save an Outlook MailItem as an .eml file as well as how to send an e-mail from an EML file.



About the Author

Robert Gravelle

Rob Gravelle combined his love of programming and music to become a software guru and accomplished guitar player. He created systems that are used by Canada Border Services, CSIS and other Intelligence-related organizations. As a software consultant, Rob has developed Web applications for many businesses and recently created a MooTools version of PHPFreechat for ViziMetrics. Musically, Rob recently embarked on a solo music career, after playing with Ivory Knight since 2000. That band was rated as one Canada's top bands by Brave Words magazine (issue #92) and released two CDs. Rob's latest, entitled KNIGHTFALL, was a collaboration between himself, the former Ivory Knight vocalist, and legendary guitarist/producer, Jeff Waters of Annihilator fame. Rob is available for short-term software projects and recording session work. to inquire, but note that, due to the volume of emails received, he cannot respond to every email. Potential jobs and praise receive highest priority!

Related Articles

Comments

  • There are no comments yet. Be the first to comment!

  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date