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.
There are comments.