Sending from a service account isn’t as easy as you’d think. There are a lot of parts to it and configuration issues on the google site of things. I’m going to document the code part, assuming you have a service account with the proper permissions already. Here are the steps:
- Set up a service account with permission to send email across the domain.
- Configure a ServiceAccountCredential, not a GoogleCredential. They’re different.
- Configure the service account credential to impersonate the sender. You have to do this during the creation, as you cannot set the sender address after the credential is set up.
- Initialize a new GmailService using the credential you created and the ApplicationName (this is what is in your api settings on google admim)
- Create an email using AE.Net.Mail.MailMessage. (you can do it raw, but seriously…. it’s a super pain in the butt if you start getting complex. Use the plugin)
- Convert the AE.Net.Mail.MailMessage to a Google.Apis.Gmail.v1.Data.Message
- Send the message, including the sender’s account as a parameter.
Prepare your Service Account
The first step is to get the private key. If you go to your cloud API management page, you should be able to download the credentials in JSON format. It should look like this:
{ "type": "service_account", "project_id": "myproject-123456", "private_key_id": "1005769f7xxxxxxxxxxxxxc7", "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEuwIBADA7d85lMp7VG+NgGkPGqCI5lwyxxxxxxxxxxxxYOUR_PRIVATE_KEYxxxxxxxxxxxxxxxxxxxxaSpwY1wXB\nzgHY67TpZevWfBV8RnnX\n-----END PRIVATE KEY-----\n", "client_email": "the.email.of@your.gserviceaccount.com", "client_id": "1234_your_app_client_id_567", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/the_service_name%40the.email.of@your.gserviceaccount.com" }
You don’t need the entire thing to set up service creds. You just need the Private Key and your service account email
/* note: the string impersonate is the FROM address. You intend to send an email from this person and have it appear in their Sent box. You are impersonating them and they HAVE TO BE included in the credentials when you make them */ private ServiceAccountCredential googleCred(string impersonate) { ServiceAccountCredential cred = new ServiceAccountCredential( new ServiceAccountCredential.Initializer("your.service@email.iam.gserviceaccount.com") { User = impersonate, Scopes = new[] { GmailService.Scope.MailGoogleCom } } .FromPrivateKey("-----BEGIN PRIVATE KEY-----\nMIIXXXX_YOUR__PRIVATE_KEY__XXXXX\n-----END PRIVATE KEY-----\n")); return cred } /* If you have issues with permissions, take a look at your api privileges here. They move the link around, so I can't promise this link is accurate https://admin.google.com/[enter your domain here]/AdminHome?chromeless=1#OGX:ManageOauthClients */
Creating an Email in the Proper Format
You’d think this is simple, but Google does not accept Microsoft’s standard format. Luckily, there is AE.Net.Mail. That’s a nice plugin that can be converted directly to a Google Mail Object. Here is a basic email being set up:
Now that you have the AE Message created, you need to convert it to a Google Message.
// this function converts our AE.Mail message to the format gmail uses. public static Message createGmailMessage(AE.Net.Mail.MailMessage mailMessage) { var messageString = new StringWriter(); mailMessage.Save(messageString); Message gmailMessage = new Message(); gmailMessage.Raw = Base64UrlEncode(messageString.ToString()); return gmailMessage; } // this function will make the base64 safe for url by doing some find-replaces 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("=", ""); }
Sending the Message
Once you’ve got the message all set up, you need to activate Google and send it!
public string SendEmail(Message gmail, string fromAddress) { var credential = this.googleCred(fromAddress); var service = new GmailService(new BaseClientService.Initializer() { HttpClientInitializer = credential, ApplicationName = "theNameOfYourApplication", }); try { var retval = service.Users.Messages.Send(gmail, fromAddress).Execute(); return retval.Id; } catch (Exception e) { Debug.Print("An error occurred: " + e.Message); return e.Message; } }
Notes: I used to following usings:
using Google.Apis.Gmail.v1; using Google.Apis.Gmail.v1.Data; using AE.Net.Mail;