Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

Create and Send An Email Reply in C# / VB.NET

5.00/5 (35 votes)
15 Jun 2016CPOL7 min read 83.8K   4.4K  
C# and VB.NET console applications that demonstrate how to create and send an email reply with IMAP and SMTP protocols in .NET Framework

Here, you can download the latest version of the demo .NET application, with C# or VB.NET source code:

(last updated on 2016-06-10)

Introduction

Some time ago, I needed a solution for sending email replies using C#. An internet search didn’t return any usable examples, so I needed to investigate it on my own. I wrote this article in the hope that it would be useful for someone trying to create and send an email message reply programmatically in a .NET application. It was mainly to save you the trouble of going through RFC documents and understanding the email message format (MIME) for which, as a developer of GemBox.Email component, I gained quite some knowledge.

Email Reply Standard

The MIME standard extends the original ASCII text-only email format to support character sets other than ASCII, non-text attachments and multipart message bodies. Although the standard is very old, it is still in use and most of today’s email messages are still sent and received in this format.

The format is specified in a few RFC documents, but since each of them has been updated, it took me a while to find the info on writing reply messages. RFC 2822 defines “identification fields”, better known as headers, which need to be defined in an email message reply. For an email message to qualify as a reply, it needs to contain the headers “In-Reply-To” and “References”.

The standard also states that you should prefix the email message subject with “Re:” (from Latin “res” meaning “in the matter of”), although it is not mandatory.

What About the Email Message Body?

It came as a surprise to me that the email message reply examples in RFC 2822 don’t include the original email message body, especially since all of the email replies in my inbox do. It’s because most of the commonly used email clients have this option enabled by default, but it can be disabled.

Although there is no standard defining the format for quoting in a plain text message, the '>' sign is the most commonly used quote prefix char. Basically, you prefix every line of the original message text with a '>' sign. You can read more about it here. For HTML message bodies, there is no standard at all. Not even a convention. You are free to include the original text any way you see fit. Most of the email clients use the <blockquote> tag, but some use the <div> tag with custom styling.

Reply message screenshot

Screenshot of an email message reply

C# / VB.NET Code

Now that we have some knowledge of the subject, we can take a look at the code.

C#
static void Main(string[] args)
{
    // Download unread messages from the server
    IEnumerable<MailMessage> messages = GetMessages();
    if (messages != null)
    {
        Console.WriteLine(messages.Count().ToString() + " new message(s).");

        // Create message replies
        List<MailMessage> replies = new List<MailMessage>();
        foreach (MailMessage msg in messages)
        {
            replies.Add(CreateReply(msg));
            msg.Dispose();
        }

        // Send replies
        SendReplies(replies);
    }
    else
    {
        Console.WriteLine("No new messages.");
    }

    Console.WriteLine("Press any key to exit...");
    Console.ReadKey();
}
VB.NET
Sub Main()
    ' Download unread messages from the server
    Dim messages As IEnumerable(Of MailMessage) = GetMessages()
    If messages IsNot Nothing Then
        Console.WriteLine(messages.Count().ToString() & " new email message(s).")

        ' Create message replies
        Dim replies As New List(Of MailMessage)()

        For Each msg As MailMessage In messages
            replies.Add(CreateReply(msg))
            msg.Dispose()
        Next

        ' Send replies
        SendReplies(replies)
    Else
        Console.WriteLine("No new email messages.")
    End If

    Console.WriteLine("Press any key to exit...")
    Console.ReadKey()
End Sub

Method Main first checks if there are any new unseen email messages on the server. If GetMessages returns a not-null enumeration of email messages, the result is enumerated and a reply message is created for each item, using the CreateReply method. Since the original email messages won’t be needed any more, they are disposed of after creating the replies. At the end, the replies are passed to the SendReplies method which will send them using System.Net.SmtpClient. Since this is a console application, progress info is displayed on the console window.

Reading Emails with an IMAP Client

There are two standard email protocols that can be used for fetching email messages, POP and IMAP. Unfortunately, the .NET framework doesn’t provide support for either of them. It supports only SMTP, which can be used only for sending email messages. The following code uses S22.Imap, a third party IMAP client for downloading messages from the server.

C#
private static IEnumerable<MailMessage> GetMessages()
{
    using (ImapClient client = new ImapClient(imapHost, 993, true))
    {
        Console.WriteLine("Connected to " + imapHost + '.');

        // Login
        client.Login(imapUser, imapPassword, AuthMethod.Auto);
        Console.WriteLine("Authenticated.");

        // Get a collection of all unseen messages in the INBOX folder
        client.DefaultMailbox = "INBOX";
        IEnumerable<uint> uids = client.Search(SearchCondition.Unseen());

        if (uids.Count() == 0)
            return null;

        return client.GetMessages(uids);
    }
}
VB.NET
Private Function GetMessages() As IEnumerable(Of MailMessage)
    Using client As New ImapClient(imapHost, 993, True)
        Console.WriteLine("Connected to " & imapHost & "."c)

        ' Login
        client.Login(imapUser, imapPassword, AuthMethod.Auto)
        Console.WriteLine("Authenticated.")

        ' Get a collection of all unseen messages in the INBOX folder
        client.DefaultMailbox = "INBOX"
        Dim uids As IEnumerable(Of UInteger) = client.Search(SearchCondition.Unseen())

        If (uids.Count = 0) Then Return Nothing

        Return client.GetMessages(uids)
    End Using
End Function

S22.Imap makes retrieving new messages a trivial task. First, you need to initialize a new ImapClient, which connects to the server. The next step is authentication, which is executed by calling the Login method with the mailbox username, password and authentication method as parameters. Use AuthMethod.Auto because it will select the best authentication method that the server supports.

The next step is to set “INBOX” as a default mailbox and query the server for all unseen messages. The method returns an enumeration of message IDs. If that enumeration is not empty, the GetMessages method is called, which will return an enumeration of System.Net.Mail.MailMessage instances for the provided message IDs.

Creating a Reply Message

After all the unseen messages have been downloaded, replies are created by calling the CreateReply method in a loop, as you can see in the following code snippet:

C#
// Create message replies
List<MailMessage> replies = new List<MailMessage>();
foreach (MailMessage msg in messages)
{
    replies.Add(CreateReply(msg));
    msg.Dispose();
}
VB.NET
' Create message replies
Dim replies As New List(Of MailMessage)()

For Each msg As MailMessage In messages
    replies.Add(CreateReply(msg))
    msg.Dispose()
Next

The CreateReply method first creates a new mail message with the sender and receiver addresses swapped.

C#
MailMessage reply = new MailMessage(new MailAddress(imapUser, "Sender"), source.From);
VB.NET
Dim reply As New MailMessage(New MailAddress(imapUser, "Sender"), source.From)

source.To cannot be used as a from parameter since it is a collection of email addresses instead of a single address and it might contain multiple addresses, so you could end up with the wrong one. In the example code, I have used a username defined for IMAP server authentication. Be sure to specify the full email address of the user as a username, when using your credentials, or it won’t work as expected.

The first thing you need to do with a reply message is to add the required headers. As explained in the Email reply standard section, these are “In-Reply-To” and “References”.

C#
string id = source.Headers["Message-ID"];
reply.Headers.Add("In-Reply-To", id);

// Try to get 'References' header from the source and add it to the reply
string references = source.Headers["References"];
if (!string.IsNullOrEmpty(references))
    references += ' ';

reply.Headers.Add("References", references + id);
VB.NET
Dim id As String = source.Headers("Message-ID")
reply.Headers.Add("In-Reply-To", id)

' Try to get 'References' header from the source and add it to the reply
Dim references As String = source.Headers("References")
If Not String.IsNullOrEmpty(references) Then references &= " "c

reply.Headers.Add("References", references & id)

Although “Message-ID” header is not mandatory, most messages will contain it, especially those from major providers like Gmail, Yahoo, Outlook, etc. For that reason, the id variable is not checked.

Next, if not already prefixed, prefix the reply subject with “Re:”.

C#
// Add subject
if (!source.Subject.StartsWith("Re:", StringComparison.OrdinalIgnoreCase))
    reply.Subject = "Re: ";

reply.Subject += source.Subject;
VB.NET
' Add subject
If Not source.Subject.StartsWith("Re:", StringComparison.OrdinalIgnoreCase) Then
    reply.Subject = "Re: "
End If

reply.Subject &= source.Subject

Finally, the reply body is composed, depending on the source message body type.

C#
StringBuilder body = new StringBuilder();
if (source.IsBodyHtml)
{
    body.Append("<p>Thank you for your email!</p>");
    body.Append("<p>We are currently out of the office, 
    but we will respond as soon as possible.</p>");
    body.Append("<p>Best regards,<br/>");
    body.Append(senderName);
    body.Append("</p>");
    body.Append("<br/>");

    body.Append("<div>");
    if (source.Date().HasValue)
        body.AppendFormat
        ("On {0},", source.Date().Value.ToString(CultureInfo.InvariantCulture));

    if (!string.IsNullOrEmpty(source.From.DisplayName))
        body.Append(source.From.DisplayName + ' ');

    body.AppendFormat("<<a href=\"mailto:{0}\">{0}</a>> 
    wrote:<br/>", source.From.Address);

    if (!string.IsNullOrEmpty(source.Body))
    {
        body.Append("<blockqoute style=\"margin: 0 0 0 5px;
        border-left:2px blue solid;padding-left:5px\">");
        body.Append(source.Body);
        body.Append("</blockquote>");
    }

    body.Append("</div>");
}
else
{
    body.AppendLine("Thank you for your email!");
    body.AppendLine();
    body.AppendLine("We are currently out of the office, 
    but we will respond as soon as possible.");
    body.AppendLine();
    body.AppendLine("Best regards,");
    body.AppendLine(senderName);
    body.AppendLine();

    if (source.Date().HasValue)
        body.AppendFormat("On {0}, 
        ", source.Date().Value.ToString(CultureInfo.InvariantCulture));

    body.Append(source.From);
    body.AppendLine(" wrote:");

    if (!string.IsNullOrEmpty(source.Body))
    {
        body.AppendLine();
        body.Append("> " + 
        source.Body.Replace("\r\n", "\r\n> "));
    }	
}

reply.Body = body.ToString();
reply.IsBodyHtml = source.IsBodyHtml;
VB.NET
Dim body As New StringBuilder()
If source.IsBodyHtml Then
    body.Append("<p>Thank you for your email!</p>")
    body.Append("<p>We are currently out of the office, _
    but we will respond as soon as possible.</p>")
    body.Append("<p>Best regards,<br/>")
    body.Append(senderName)
    body.Append("</p>")
    body.Append("<br/>")

    body.Append("<div>")
    If source.Date().HasValue Then body.AppendFormat("On {0}, _
    ", source.Date().Value.ToString(CultureInfo.InvariantCulture))
    If Not String.IsNullOrEmpty(source.From.DisplayName) _
    Then body.Append(source.From.DisplayName & " "c)

    body.AppendFormat("<<a href=""mailto:{0}"">_
    {0}</a>> wrote:<br/>", source.From.Address)

    If Not String.IsNullOrEmpty(source.Body) Then
        body.Append("<blockqoute style=""margin:0 0 0 5px;_
        border-left:2px blue solid;padding-left:5px"">")
        body.Append(source.Body)
        body.Append("</blockquote>")
    End If

    body.Append("</div>")
Else
    body.AppendLine("Thank you for your email!")
    body.AppendLine()
    body.AppendLine("We are currently out of the office, _
    but we will reply as soon as possible.")
    body.AppendLine()
    body.AppendLine("Best regards,")
    body.AppendLine(senderName)
    body.AppendLine()

    If source.Date().HasValue Then body.AppendFormat("On {0}, _
    ", source.Date().Value.ToString(CultureInfo.InvariantCulture))

    body.Append(source.From)
    body.AppendLine(" wrote:")

    If Not String.IsNullOrEmpty(source.Body) Then
        body.AppendLine()
        body.Append("> " & source.Body.Replace(vbCrLf, vbCrLf & ">"c))
    End If
End If

reply.Body = body.ToString()
reply.IsBodyHtml = source.IsBodyHtml

I have used very simple text for the reply body, but you can see that the <blockqoute> tag is used for the HTML body and the '>' prefix for the plain text body.

Sending Emails with an SMTP Client

Newly created message replies are sent using the standard .NET SmtpClient. The process is quite straightforward as you can see in the code below:

C#
using (SmtpClient client = new SmtpClient(smtpHost, 587))
{
    // Set SMTP client properties
    client.EnableSsl = true;
    client.UseDefaultCredentials = false;
    client.Credentials = new NetworkCredential(smtpUser, smtpPassword);
    client.DeliveryFormat = SmtpDeliveryFormat.International;

    // Send
    bool retry = true;
    foreach (MailMessage msg in replies)
    {
        try
        {
            client.Send(msg);
            retry = true;
        }
        catch (Exception ex)
        {
            if (!retry)
            {
                Console.WriteLine("Failed to send reply to " +
                msg.To.ToString() + '.');
                Console.WriteLine("Exception: " + ex.Message);
                return;
            }

            retry = false;
        }
        finally
        {
            msg.Dispose();
        }
    }

    Console.WriteLine("All replies successfully sent.");
}
VB.NET
Using client As New SmtpClient(smtpHost, 587)
    ' Set SMTP client properties
    client.EnableSsl = True
    client.UseDefaultCredentials = False
    client.Credentials = New NetworkCredential(smtpUser, smtpPassword)

    ' Send
    Dim retry As Boolean = True
    For Each msg As MailMessage In replies
        Try
            client.Send(msg)
            retry = True
        Catch ex As Exception
            If Not retry Then
                Console.WriteLine("Failed to send email reply to _
                " & msg.To.ToString() & "."c)
                Console.WriteLine("Exception: " & ex.Message)
                Exit Sub
            End If

            retry = False
        Finally
            msg.Dispose()
        End Try
    Next

    Console.WriteLine("All email replies successfully sent.")

To prevent the application from crashing on single message errors, all exceptions are ignored. Still, there might be an error with the SMTP server or credentials that will cause every message to fail, so for that reason, I have used a very simple and primitive retry pattern. Basically, it uses a bool variable to break the sending loop when there are two exceptions in a row.

Application console screenshot

Screenshot of the EmailReply application’s console window

Alternatives

Since the .NET Framework doesn’t provide any means for downloading email messages from the server, the code presented in this article uses the S22.Imap component for that task. As the name suggests, the library communicates with the server using the IMAP protocol. Another very commonly used protocol is POP, and there are even more components for it on the internet since POP is a much older and simpler protocol. OpenPop is the most popular, but S22.Pop3 is a good choice as well since it uses the System.Net.Mail.MailMessage class instead of the custom message class used by OpenPop.

Gmail Security

Being one of the most used email providers, Google’s Gmail service has very high security standards. By default, POP, IMAP and common authentication mechanisms are disabled. To be able to use your Gmail account in the demo application supplied with this article, you need to do the following:

Enable POP or IMAP Access for Your Account

  1. Log in to your Gmail account and select 'Settings' from the right side menu.

    Gmail setings menu
  2. Select the 'Forwarding and POP/IMAP' tab and enable POP or IMAP, depending on which protocol you are going to use.

    Forwarding and POP/IMAP settings

Allow Access for Less Secure Applications

  1. Click on your account icon in the top right corner and select 'My Account'.

    Goggle account menu
  2. Click on 'Sign-in & security' and, at the bottom of the page, set 'Allow less secure apps:' to ON.

    Allow less secure apps: ON

Conclusion

The aim of this article was to show that creating an email message reply is quite simple. All you need to do is add headers: “In-Reply-To” and “References”. Everything else is optional. I hope this article and the attached console application will help you with your future .NET email applications.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)