Sample code to send email via gmail in c# (updated)

I wrote a post recently with some code to send email via gmail in c#. The other day, I needed to update it to allow for multiple attachments. Rather than update the original post, I’ve written this new one… (The rest is copied and pasted, altered for the new code.)


For some time, I’ve had a block of code that I copied and pasted all over the place, to send emails via gmail. It didn’t add an attachment, but I needed to do so today. So rather than copy and paste it yet again, I’ve created a simple static class that can be reused.

Note that:

  1. I hard-code my gmail address (the username) and my password as constants. (Changed to invalid values here.) You’ll need to change them to something valid.
  2. When debugging, I don’t use gmail. I use an application called Papercut, and there is a similar one called smtp4dev I think… to mock a local SMTP server. It then “receives” the email.
  3. I don’t do anything if there is an exception when trying to send the email. That’s because the applications using this code typically send emails from their exception handlers when there are errors. You might want to do something different.
  4. I’m not going to explain how to enable SMTP on a gmail account. I trust that anybody using this can figure that out for themselves.

This is really simple code, and I consider it junior developer level. I’m just putting it here, to make it easier to reuse. Please don’t ask me any questions about it. It does the basic job I need it to do and that’s all.

I’ll paste an example that uses it below…

using System.Collections.Generic;
using System.Net.Mail;

namespace Example
{
    public static class EmailHandler
    {
        private const string UserName = "name@gmail.com";
        private const string Password = "YourPasswordHere";

        public static void SendEmail(IEnumerable<string> toAddresses, IEnumerable<string> copyAddresses, IEnumerable<string> bccAddresses, 
            string subject, string from, string body, IEnumerable<Attachment> attachments = null, bool isHtml = true)
        {
            using (MailMessage mailMessage = new MailMessage())
            {
                foreach (var to in toAddresses)
                    mailMessage.To.Add(to);

                foreach (var copy in copyAddresses)
                    mailMessage.CC.Add(copy);

                foreach (var copy in bccAddresses)
                    mailMessage.Bcc.Add(copy);

                mailMessage.Subject = subject;

                mailMessage.From = new MailAddress(from);
                mailMessage.Body = body;
                mailMessage.IsBodyHtml = isHtml;

                if (attachments != null)
                {
                    foreach (var attachment in attachments)
                        mailMessage.Attachments.Add(attachment);
                }

                try
                {
#if DEBUG
                    using (SmtpClient smtp = new SmtpClient("127.0.0.1"))
                    {
                        smtp.EnableSsl = false;
                        smtp.Port = 25;
                        smtp.Send(mailMessage);
                    }
#else
                            using (SmtpClient smtp = new SmtpClient("smtp.gmail.com", 587)
                            {
                                Credentials = new System.Net.NetworkCredential(UserName, Password),
                                EnableSsl = true
                            })
                            {
                                smtp.Send(mailMessage);
                            }
#endif
                }
                catch { }
            }
        }
    }
}

In my example that uses the above, I’m calling it from ASP.Net. The attachment I pass to it is a PDF rendered from an SSRS report, using the ReportViewer control. You shouldn’t really need this code, except for the part that initializes the attachment, because it may not be obvious how to do that. The attachment can be initialized via a file name or stream, and needs a MIME type. I use the constructor that takes a stream, a file name, and the content type name. Bizarrely there is also one that takes a content type itself and a stream, without a file name. That one is kind of shitty.

The update… My example code still uses an SSRS report that gets rendered to PDF, but the site also allows the user to upload files. I’m using DevExpress controls, and as each file is uploaded to the site, I put the contents in the session. The code to clear those variables, which is not shown, is called after sending or cancelling sending the email… Just so you can see what’s in the session, the handler for each uploaded file looks like this:

protected void ASPxUploadControl1_FileUploadComplete(object sender, DevExpress.Web.ASPxUploadControl.FileUploadCompleteEventArgs e)
{
    e.CallbackData = e.UploadedFile.FileName;

    Dictionary<string, byte[]> attachments = Session["Attachments"] == null ? new Dictionary<string, byte[]>() : (Dictionary<string, byte[]>)Session["Attachments"];

    attachments[e.UploadedFile.FileName] = e.UploadedFile.FileBytes;

    Session["Attachments"] = attachments;
}

Here is the updated code that sends the email. Note that the handling of attachments is a little messy. For each attachment, I use a Stream to initialize the attachment object, but all those streams need to remain in scope while the email is being sent. Then they are all closed afterwards. So I couldn’t use a using statement, as I normally would…

So this example looks more complicated than it actually is. Code to use the wrapper to send a simple email would be trivial. I trust that most developers, even junior ones, should be able to use my wrapper without reading the example code.

protected void cbSendEmail_Callback(object source, DevExpress.Web.ASPxCallback.CallbackEventArgs e)
{
    string[] toEmails = ((string)flEmail.GetNestedControlValueByFieldName("ToEmail")).Replace(";", ",").Split(',');

    if (toEmails.Length > 0)
    {
        string subject = (string)flEmail.GetNestedControlValueByFieldName("Subject");

        string body = htmlMessage.Html;

        int id = (int)Session["InvoiceID"];
        ReportParameter p = new ReportParameter("ClientInvoiceID", id.ToString());

        reportViewer.ServerReport.SetParameters(new ReportParameter[] { p });
        byte[] data = reportViewer.ServerReport.Render("pdf");

        string invoiceNumber = (string)queryHandler.OpenQuery("SELECT InvoiceNumber FROM ClientInvoice WHERE ID = @ID", new Dictionary<string, object> { { "@ID", id } }).Rows[0]["InvoiceNumber"];

        Dictionary<string, byte[]> attachments = Session["Attachments"] == null ? new Dictionary<string, byte[]>() : (Dictionary<string, byte[]>)Session["Attachments"];

        using (MemoryStream stream = new MemoryStream(data))
        {
            System.Net.Mail.Attachment attachment = new System.Net.Mail.Attachment(stream, string.Format("Invoice {0}.pdf", invoiceNumber), System.Net.Mime.MediaTypeNames.Application.Pdf);

            var emailAttachments = new List<System.Net.Mail.Attachment>();

            emailAttachments.Add(attachment);

            List<Stream> streams = new List<Stream>();

            try
            {
                foreach (var kvp in attachments)
                {
                    streams.Add(new MemoryStream(kvp.Value));
                    emailAttachments.Add(new System.Net.Mail.Attachment(streams[streams.Count - 1], kvp.Key));
                }

                EmailHandler.SendEmail(toEmails, Enumerable.Empty<string>(), new string[] { "redacted@someplace.co.za" }, subject, "redacted@someplace.co.za", body, emailAttachments);
            }
            finally
            {
                foreach (var memStream in streams)
                    stream.Close();
            }
        }
    }
}
Advertisements

About Jerome

I am a senior C# developer in Johannesburg, South Africa. I am also a recovering addict, who spent nearly eight years using methamphetamine. I write on my recovery blog about my lessons learned and sometimes give advice to others who have made similar mistakes, often from my viewpoint as an atheist, and I also write some C# programming articles on my programming blog.
This entry was posted in Programming and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s