Sending Email with the Gmail API in .NET / C#

I've a .NET web application with several Google API integrations and wanted to send Gmail as well. It took me all day, and I found precious little (useful) documentation, so it seemed worth a blog post.

At the start of the day I already had OAuth2 talking with Google. I did have to tweak my setup a bit, but authentication was already a solved problem with my integration.

I had to pull in two NuGet packages to get it to work:

Install-Package Google.Apis.Gmail.v1
Install-Package AE.Net.Mail

Update: In the comments below, Jon notes that using ``MimeKit`` instead of ``AE.Net.Mail`` makes it easier to send HTML-formatted email.

And here's the code that sent an email:

using System.IO;
using System.Net.Mail;
using Google.Apis.Gmail.v1;
using Google.Apis.Gmail.v1.Data;

public class TestEmail {

  public void SendIt() {
    var msg = new AE.Net.Mail.MailMessage {
      Subject = "Your Subject",
      Body = "Hello, World, from Gmail API!",
      From = new MailAddress("[you]@gmail.com")
    };
    msg.To.Add(new MailAddress("yourbuddy@gmail.com"));
    msg.ReplyTo.Add(msg.From); // Bounces without this!!
    var msgStr = new StringWriter();
    msg.Save(msgStr);

    // Context is a separate bit of code that provides OAuth context;
    // your construction of GmailService will be different from mine.
    var gmail = new GmailService(Context.GoogleOAuthInitializer);
    var result = gmail.Users.Messages.Send(new Message {
      Raw = Base64UrlEncode(msgStr.ToString())
    }, "me").Execute();
    Console.WriteLine("Message ID {0} sent.", result.Id);
  }

  private static string Base64UrlEncode(string input) {
    var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
    // Special "url-safe" base64 encode.
    return Convert.ToBase64String(inputBytes)
      .Replace('+', '-')
      .Replace('/', '_')
      .Replace("=", "");
  }
}

Why?

The .NET code samples in the Google documentation don't tell you how to instantiate the Message class. That's the hard part. There is a deep and complicated structure to it, and I couldn't get it to work. The Google Service complained, basically saying, "I want you to use the Raw property." And the Raw property is, well, raw: "The entire email message in an RFC 2822 formatted and URL-safe base64 encoded string." Couple tricks here:

  • RFC 2822 is complicated.
  • System.Net.Mail.MailMessage doesn't give access to the raw data (even though it must implement RFC 2822 internally).
  • URL-safe base64 encoding isn't exactly what Convert.ToBase64String does.

Thankfully AE.Net.Mail.MailMessage provides the Save() method to get the raw RFC 2822 message, and just a little tweaking is necessary to get a URL-Safe base 64 encoding.

Hope saves someone some time! I did a lot of Googling today, and an article like this one would have saved me a ton of time.

Comments !

links

social