Can we access GMAIL API using Service Account? - c#

I have a desktop application to read mail using GMAIL API over REST Interface. I want to use service account so that we can download the mails using domain setting and user interaction is null. I am successfully able to create Gmail Service instance but when I try to access any Gmail API method like fetching mail list or any other I get an exception saying
Google.Apis.Auth.OAuth2.Responses.TokenResponseException:
Error:"access_denied", Description:"Requested client not
authorized."
I am done with all the setting at developer console and added scopes to my gapps domain.
Does Gmail API support service account? Using the same setting and service account I am able to get list of all files in Google drive using Drive service and API.

I use the following C# code for accessing Gmail from Service Account
String serviceAccountEmail =
"999999999-9nqenknknknpmdvif7onn2kvusnqct2c#developer.gserviceaccount.com";
var certificate = new X509Certificate2(
AppDomain.CurrentDomain.BaseDirectory +
"certs//fe433c710f4980a8cc3dda83e54cf7c3bb242a46-privatekey.p12",
"notasecret",
X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
string userEmail = "user#domainhere.com.au";
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
User = userEmail,
Scopes = new[] { "https://mail.google.com/" }
}.FromCertificate(certificate)
);
if (credential.RequestAccessTokenAsync(CancellationToken.None).Result)
{
GmailService gs = new GmailService(
new Google.Apis.Services.BaseClientService.Initializer()
{
ApplicationName = "iLink",
HttpClientInitializer = credential
}
);
UsersResource.MessagesResource.GetRequest gr =
gs.Users.Messages.Get(userEmail, msgId);
gr.Format = UsersResource.MessagesResource.GetRequest.FormatEnum.Raw;
Message m = gr.Execute();
if (gr.Format == UsersResource.MessagesResource.GetRequest.FormatEnum.Raw)
{
byte[] decodedByte = FromBase64ForUrlString(m.Raw);
string base64Encoded = Convert.ToString(decodedByte);
MailMessage msg = new MailMessage();
msg.LoadMessage(decodedByte);
}
}

Here is a little bit of python 3.7:
from google.oauth2 import service_account
from googleapiclient.discovery import build
def setup_credentials():
key_path = 'gmailsignatureproject-zzz.json'
API_scopes =['https://www.googleapis.com/auth/gmail.settings.basic',
'https://www.googleapis.com/auth/gmail.settings.sharing']
credentials = service_account.Credentials.from_service_account_file(key_path,scopes=API_scopes)
return credentials
def test_setup_credentials():
credentials = setup_credentials()
assert credentials
def test_fetch_user_info():
credentials = setup_credentials()
credentials_delegated = credentials.with_subject("tim#vci.com.au")
gmail_service = build("gmail","v1",credentials=credentials_delegated)
addresses = gmail_service.users().settings().sendAs().list(userId='me').execute()
assert gmail_service

If you want to "read mail" you'll need the newer Gmail API (not the older admin settings API that 'lost in binary' pointed out). Yes you can do this with oauth2 and the newer Gmail API, you need to whitelist the developer in Cpanel and create a key you can sign your requests with--it take a little bit to setup:
https://developers.google.com/accounts/docs/OAuth2ServiceAccount#formingclaimset

For C# Gmail API v1, you can use the following code to get the gmail service. Use gmail service to read emails. Once you create the service account in Google Console site, download the key file in json format. Assuming the file name is
"service.json".
public static GoogleCredential GetCredenetial(string serviceAccountCredentialJsonFilePath)
{
GoogleCredential credential;
using (var stream = new FileStream(serviceAccountCredentialJsonFilePath, FileMode.Open, FileAccess.Read))
{
credential = GoogleCredential.FromStream(stream)
.CreateScoped(new[] {GmailService.Scope.GmailReadonly})
.CreateWithUser(**impersonateEmail#email.com**);
}
return credential;
}
public static GmailService GetGmailService(GoogleCredential credential)
{
return new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Automation App",
});
}
// how to use
public static void main()
{
var credential = GetCredenetial("service.json");
var gmailService = GetGmailService(credential);
// you can use gmail service to retrieve emails.
var mMailListRequest = gmailService.Users.Messages.List("me");
mMailListRequest.LabelIds = "INBOX";
var mailListResponse = mMailListRequest.Execute();
}

Yes you can... check the delegation settings...
https://developers.google.com/admin-sdk/directory/v1/guides/delegation#delegate_domain-wide_authority_to_your_service_account
Edit: Use the link Eric DeFriez shared.

You can access any user#YOUR_DOMAIN.COM mails/labels/threads etc. with the new Gmail API:
https://developers.google.com/gmail/api/
via service account with impersonation (service account is accessing api as if it was specific user from your domain).
See details here: https://developers.google.com/identity/protocols/OAuth2ServiceAccount
Here is relevant code in Dartlang:
import 'package:googleapis_auth/auth_io.dart' as auth;
import 'package:googleapis/gmail/v1.dart' as gmail;
import 'package:http/http.dart' as http;
///credentials created with service_account here https://console.developers.google.com/apis/credentials/?project=YOUR_PROJECT_ID
final String creds = r'''
{
"private_key_id": "FILL_private_key_id",
"private_key": "FILL_private_key",
"client_email": "FILL_service_account_email",
"client_id": "FILL_client_id",
"type": "service_account"
}''';
Future<http.Client> createImpersonatedClient(String impersonatedUserEmail, List scopes) async {
var impersonatedCredentials = new auth.ServiceAccountCredentials.fromJson(creds,impersonatedUser: impersonatedUserEmail);
return auth.clientViaServiceAccount(impersonatedCredentials , scopes);
}
getUserEmails(String userEmail) async { //userEmail from YOUR_DOMAIN.COM
var client = await createImpersonatedClient(userEmail, [gmail.GmailApi.MailGoogleComScope]);
var gmailApi = new gmail.GmailApi(client);
return gmailApi.users.messages.list(userEmail, maxResults: 5);
}

Related

Error while trying to send email from google workspace from asp.net core web api app using Google.Apis.Gmail

I'm trying to send email from my google workspace account using this code:
using (var stream =
new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
{
var credential = ServiceAccountCredential.FromServiceAccountData(stream);
service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
var email = MimeMessage.CreateFromMailMessage(new System.Net.Mail.MailMessage("EMAILADDRESS", destinationEmailAddress, "Verification code", $"Your verification code is {messageBody}"));
Message message = new Message();
byte[] blob;
using (var memory = new MemoryStream())
{
email.WriteTo(memory);
blob = memory.ToArray();
}
message.Raw = await credential.SignBlobAsync(blob);
await service.Users.Messages.Send(message, "me").ExecuteAsync();
}
but I get the following exception:
Google.Apis.Requests.RequestError\nPrecondition check failed. [400]\nErrors [\n\tMessage[Precondition check failed.] Location[ - ] Reason[failedPrecondition] Domain[global]\n]\n
what am I doing wrong? and is there a straight forward guide to do this right?
The issue you are having is that you are using Gmail with a service account and you have not properly configured domain wide delegation to a user on your workspace account. Follow this guide to configure your workspace account with the service account. Perform Google Workspace Domain-Wide Delegation of Authority
The following code should show you how to authorize it. Note the CreateWithUser method this sets up the user you wish to delegate the service account as.
class Program
{
private static readonly string[] Scopes = {GmailService.Scope.GmailSend};
private static readonly string PathToServiceAccountKeyFile =
#"C:\YouTube\workspaceserviceaccount-e4823a933ae3.json";
private static readonly string workspaceAdmin = "xxxx#daimto.com";
private static readonly string sendEmailTo = "xxxx#gmail.com";
static async Task Main(string[] args)
{
Console.WriteLine("Hello World!");
var credential = LoadGoogleCredentials();
var service = CreateDirectoryService(credential);
var mailMessage = new System.Net.Mail.MailMessage
{
From = new System.Net.Mail.MailAddress(workspaceAdmin),
ReplyToList = {workspaceAdmin},
To = {sendEmailTo},
Subject = "Welcome",
Body = "welcome new workspace user",
};
var mimeMessage = MimeMessage.CreateFromMailMessage(mailMessage);
var gmailMessage = new Message
{
Raw = Encode(mimeMessage)
};
var request = await service.Users.Messages.Send(gmailMessage, workspaceAdmin).ExecuteAsync();
Console.ReadLine();
}
public static string Encode(MimeMessage mimeMessage)
{
using (MemoryStream ms = new MemoryStream())
{
mimeMessage.WriteTo(ms);
return Convert.ToBase64String(ms.GetBuffer())
.TrimEnd('=')
.Replace('+', '-')
.Replace('/', '_');
}
}
private static GmailService CreateDirectoryService(GoogleCredential credential)
{
return new(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Daimto Testing Workspace with service account"
}
);
}
private static GoogleCredential LoadGoogleCredentials()
{
return GoogleCredential.FromFile(PathToServiceAccountKeyFile)
.CreateScoped(Scopes)
.CreateWithUser(workspaceAdmin);
}
}
Note: this code is the same for all types of applications even though my test code is a console app the methods used will work for your asp .net core app as well
from comments
Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested
this error message means that your servcie account is not authorized with the proper scope. the gmail send method requires a scope that allows access to sending emails GmailService.Scope.GmailSend for instance as i have use din my code remember to add it in workspace as well.
Full tutorial Gmail api with google workspace and .net

Integrating with Google Admin SDK in C#

I'm currently trying to integrate with the Google Admin SDK via C# so we can manage users via our own system. However, when running the project I get the error: Unauthorized Client.
Things I have already done via a super admin account:
Setup Service Account
Enabled GSuite domain-wide delegation on service Account
Enabled API Access
Added the Service Accounts client ID to API Client Access with the scope (https://www.googleapis.com/auth/admin.directory.user)
Here's the code that i'm using.
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(_googleServiceSettings.Client_Email)
{
ProjectId = _googleServiceSettings.Project_Id,
User = "superadmin#google.com",
Scopes = new[] { DirectoryService.Scope.AdminDirectoryUser }
}.FromPrivateKey(_googleServiceSettings.Private_Key));
var service = new DirectoryService(new BaseClientService.Initializer
{
HttpClientInitializer = credential,
ApplicationName = "Test API"
});
var request = service.Users.Get("user#google.com");
var result = await request.ExecuteAsync();
The full error i'm getting is
An unhandled exception has occurred while executing the request.
Google.Apis.Auth.OAuth2.Responses.TokenResponseException: Error:"unauthorized_client", Description:"Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested.", Uri:""
Example code that will print some information about a user.
The important item is the class Google.Apis.Admin.Directory.directory_v1.Data.User
Documentation link.
Your error is caused by not creating the credentials correctly. Usually, an issue with scopes when creating the credentials. I am assuming that you have Domain-Wide Delegation setup correctly for the service account.
I am also assuming that the user that you are impersonating is a G Suite Super Admin. If not, you will see a 403 error for service.Users.Get().
The file service_account.json is a normal JSON file that you downloaded from the Google Console (or created with gcloud).
The user user1#example.com is the email address for the G Suite user for which information will be displayed.
The user admin#example.com is the G Suite Super Admin.
using Google.Apis.Auth.OAuth2;
using Google.Apis.Admin.Directory.directory_v1;
using Google.Apis.Admin.Directory.directory_v1.Data;
using Google.Apis.Services;
using System;
using System.IO;
// dotnet add package Google.Apis.Admin.Directory.directory_v1
// Tested with version 1.39.0.1505
// Google.Apis.Admin.Directory.directory_v1.Data.User
// https://developers.google.com/resources/api-libraries/documentation/admin/directory_v1/csharp/latest/classGoogle_1_1Apis_1_1Admin_1_1Directory_1_1directory__v1_1_1Data_1_1User.html
namespace Example
{
class Program
{
static void Main(string[] args)
{
// Service Account with Domain-Wide delegation
var sa_file = "service_account.json";
// G Suite User to impersonate
var user_email = "admin#example.com";
// G Suite User to get information about
var gs_email = "user1#example.com";
// Scopes
var scopes = "https://www.googleapis.com/auth/admin.directory.user";
var credential = GoogleCredential.FromFile(sa_file)
.CreateScoped(scopes)
.CreateWithUser(user_email);
// Create Directory API service.
var service = new DirectoryService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential
});
try {
var request = service.Users.Get(gs_email);
var result = request.Execute();
Console.WriteLine("Full Name: {0}", result.Name.FullName);
Console.WriteLine("Email: {0}", result.PrimaryEmail);
Console.WriteLine("ID: {0}", result.Id);
Console.WriteLine("Is Admin: {0}", result.IsAdmin);
} catch {
Console.WriteLine("User not found.");
}
}
}
}
If you want to use the service account you can authenticate with below code.
String serviceAccountEmail = "yourserviceaccountmail";
public GmailService GetService(string user_email_address)
{
var certificate = new X509Certificate2(#"yourkeyfile.p12",
"notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
User = user_email_address,
Scopes = new[] { GmailService.Scope.MailGoogleCom }
}.FromCertificate(certificate));
GmailService service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = AppName,
});
return service;
}
You can list users using this service. Its work for me.
And you can list userlist with below code. ( with DirectoryService)
public Users GetDirService()//UserList with DirectoryService
{
string Admin_Email = "yoursuperadminemail";
string domain = "yourdomain.com";
try
{
var certificate = new X509Certificate2(#"yourkeyfile.p12", "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credentialUsers = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { DirectoryService.Scope.AdminDirectoryUser },
User = Admin_Email,
}.FromCertificate(certificate));
var serviceUsers = new DirectoryService(new BaseClientService.Initializer()
{
HttpClientInitializer = credentialUsers,
ApplicationName = AppName,
});
var listReq = serviceUsers.Users.List();
listReq.Domain = domain;
Users users = listReq.Execute();
return users;
}
catch (Exception ex)
{
MessageBox.Show("your mail address must be super admin authorized.", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
return null;
}
}
Ok I have solved the issue.
Adding the following scope via the security settings within the Google Portal has solved the issue. This is strange as their own example doesn't require this scope to be added ad their documentation doesn't say it's required for this method.
https://www.googleapis.com/auth/admin.directory.group

Failure of delegation of Google Drive access to a service account

I've been involved with building an internal-use application through which users may upload files, to be stored within Google Drive. As it is recommended not to use service accounts as file owners, I wanted to have the application upload on behalf of a designated user account, to which the company sysadmin has access.
I have created the application, along with a service account. There are two keys created for the service account, as I have tried both the JSON and PKCS12 formats trying to achieve this:
I have downloaded the OAuth 2.0 client ID details, and also have the .json and .p12 files for the service account keys (in that order as displayed above):
I had my sysadmin go through the steps detailed here to delegate authority for Drive API access to the service account: https://developers.google.com/drive/v2/web/delegation#delegate_domain-wide_authority_to_your_service_account
We found that the only thing that worked for the "Client name" in step 4 was the "Client ID" listed for the Web application (ending .apps.googleusercontent.com). The long hexadecimal IDs listed for the Service account keys were not what it required (see below):
Previously to the above, I had code which would create a DriveService instance that could upload directly to the service account, referencing the .json file for the service account keys:
private DriveService GetServiceA()
{
var settings = SettingsProvider.GetInstance();
string keyFilePath = HostingEnvironment.MapPath("~/App_Data/keyfile.json");
var scopes = new string[] { DriveService.Scope.Drive };
var stream = new IO.FileStream(keyFilePath, IO.FileMode.Open, IO.FileAccess.Read);
var credential = GoogleCredential.FromStream(stream);
credential = credential.CreateScoped(scopes);
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "MyAppName"
});
return service;
}
That works for listing and uploading, though of course there's no web UI for access to the files, and it seems as though it doesn't handle things like permissions metadata or generation of thumbnails for e.g. PDFs. This is why I'm trying to use a standard account for the uploads.
Once the delegation was apparently sorted, I then attempted to adapt the code shown in the delegation reference linked above, combining with code from elsewhere for extracting the necessary details from the .json key file. With this code, as soon as I try to execute any API command, even as simple as:
FileList fileList = service.FileList().Execute();
I receive an error:
Exception Details: Google.Apis.Auth.OAuth2.Responses.TokenResponseException: Error:"unauthorized_client", Description:"Unauthorized client or scope in request.", Uri:""
The code for that effort is:
private DriveService GetServiceB()
{
var settings = SettingsProvider.GetInstance();
string keyFilePath = HostingEnvironment.MapPath("~/App_Data/keyfile.json");
string serviceAccountEmail = "<account-email>#<project-id>.iam.gserviceaccount.com";
var scopes = new string[] { DriveService.Scope.Drive };
var stream = new IO.FileStream(keyFilePath, IO.FileMode.Open, IO.FileAccess.Read);
var reader = new IO.StreamReader(stream);
string jsonCreds = reader.ReadToEnd();
var o = JObject.Parse(jsonCreds);
string privateKey = o["private_key"].ToString();
var credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = scopes,
User = "designated.user#sameappsdomain.com"
}
.FromPrivateKey(privateKey)
);
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "MyAppName"
});
return service;
}
Finally, I created the second service account key to save a .p12 file in order to more closely match the code in the authority delegation documentation, but which results in the same exception:
private DriveService GetServiceC()
{
var settings = SettingsProvider.GetInstance();
string p12KeyFilePath = HostingEnvironment.MapPath("~/App_Data/keyfile.p12");
string serviceAccountEmail = "<account-email>#<project-id>.iam.gserviceaccount.com";
var scopes = new string[] { DriveService.Scope.Drive }; // Full access
X509Certificate2 certificate = new X509Certificate2(
p12KeyFilePath,
"notasecret",
X509KeyStorageFlags.Exportable
);
var credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = scopes,
User = "designated.user#sameappsdomain.com"
}
.FromCertificate(certificate)
);
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "MyAppName"
});
return service;
}
The minimial relevant class where this method lives is:
public class GoogleDrive
{
public DriveService Service { get; private set; }
public GoogleDrive()
{
this.Service = this.GetService();
}
private DriveService GetService()
{
// Code from either A, B or C
}
public FilesResource.ListRequest FileList()
{
return this.Service.Files.List();
}
}
And that's used in this fashion:
var service = new GoogleDrive();
FilesResource.ListRequest listRequest = service.FileList();
FileList fileList = listRequest.Execute();
The exception occurs on that last line.
I do not understand why my service account cannot act on behalf of the designated user, which is part of the domain for which the application's service account should have delegated authority. What is it that I've misunderstood here?
I have found the answer myself, and it was configuration, not code. The link I shared with the steps for delegation of authority does not mention an option available when creating the service account: a checkbox saying that the account will be eligible for domain-wide delegation (DwD).
This link describes the service account creation and delegation more accurately: https://developers.google.com/identity/protocols/OAuth2ServiceAccount
I did not know about DwD when I created the service account, and so I had not selected that option. It is possible to go back and edit a service account to select it. Once I did this, I was able to retrieve a correct client ID for use in the "Manage API Client Access" part of the admin console. Using the GetServiceC() method then works as intended, and I am able to retrieve files for users in the same Apps domain.
This is the checkbox that needs to be ticked for a service account to be eligible for domain-wide delegation of authority:
This is the extra information available once you've done that (with a throwaway service account alongside that did not have the box ticked, for comparison):
You may tick the checkbox Enable G Suite Domain-wide Delegation, when you create the service account on the admin panel.
Regards
Most everything looks ok but:
A. Use ServiceC code, not sure if the object typing matters but your line:
var credential = new ServiceAccountCredential...
should be
ServiceAccountCredential credential = new ServiceAccountCredential...
B. Check that the P12 file in ServiceC is the real P12 file you actually uploaded to your environment where you're running this.
C. update your question with the exact runable code you're using to create and invoke your service:filelist:execute code. This way there's more clarity and less assumptions.

Server-side task to query Office 365 account for new emails

I need a server-side task on my .NET 4.6.1/MVC 5 app that will periodically check a specific O365 email address for new emails and retrieve them if found. This seems like a stupidly simple task, but I cannot find documentation anywhere for creating a server-side process to accomplish this. The only documentation Microsoft seems to have is for OAuth2 and passing through credentials when users sign in. I don't want that. I want to check one specific account, that's it. How would I accomplish this?
These are the pages I've found. There are others, but all are along these lines.
Intro to the Outlook API - I don't see a way to use a service account with the v2 endpoint.
Get Started with the Outlook REST APIs - This is specific to logging users in with OAuth2, unhelpful for my purposes.
Intro to the Outlook API - I don't see a way to use a service account with the v2 endpoint.
The v2 endpoint doesn’t support client credential at present( refer to the limitation). You need to register/configure the app using Azure portal and use the original endpoint to authenticate the app. More detail about register the app please refer to here. And we need to ‘read mail in all mailbox’ to use the client credential to read the messages like figure below.
And here is the code that using client credential to read messages using the Microsoft Graph:
string clientId = "";
string clientsecret = "";
string tenant = "";
string resourceURL = "https://graph.microsoft.com";
string authority = "https://login.microsoftonline.com/" + tenant + "/oauth2/token";
string userMail = "";
var accessToken = new TokenHelper(authority).AcquireTokenAsync(clientId, clientsecret, resourceURL);
var graphserviceClient = new GraphServiceClient(
new DelegateAuthenticationProvider(
(requestMessage) =>
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
return Task.FromResult(0);
}));
var items = await graphserviceClient.Users[user].Messages.Request().OrderBy("receivedDateTime desc").GetAsync();
foreach (var item in items)
{
Console.WriteLine(item.Subject);
}
class TokenHelper
{
AuthenticationContext authContext;
public TokenHelper(string authUri)
{
authContext = new AuthenticationContext(authUri);
}
public string AcquireTokenAsync(string clientId, string secret,string resrouceURL)
{
var credential = new ClientCredential(clientId: clientId, clientSecret: secret);
var result = authContext.AcquireTokenAsync(resrouceURL, credential).Result;
return result.AccessToken;
}
}
In addition, if we authenticate the app with code grant flow we can also create a subscription which notify the app when the mail box receive the new messages.( refer to webhoocks/subscription)

How can Gmail's Mail be accessed by IMAP using OAuth2 authentication or retrieve using Gmail API in asp.net c#?

is there any way for accessing Gmail's Mail by IMAP using OAUTH2 authentication in asp.net c#?
using google api, I am able to get the MessageID. But unable to retrieve the details of that message:
var gmailservice = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = appName,
});
List<Message> objList = ListMessages(gmailservice, "me", AnyFromEmailAddress);
foreach (Message objM in objList)
{
// I can retrieve objM.Id but how to get message detail?
}
Or is there any free IMAP client which use OAUTH2 for login like Limilab's Mail.dll
Using MailKit and Google's OAuth2 framework from NuGet, you can do it like this:
using (var client = new ImapClient ()) {
client.Connect ("imap.gmail.com", 993, true);
var certificate = new X509Certificate2 (#"C:\path\to\certificate.p12", "password", X509KeyStorageFlags.Exportable);
var credential = new ServiceAccountCredential (new ServiceAccountCredential.Initializer ("your-developer-id#developer.gserviceaccount.com") {
// Note: other scopes can be found here: https://developers.google.com/gmail/api/auth/scopes
Scopes = new[] { "https://mail.google.com/" },
User = "user#gmail.com"
}.FromCertificate (certificate));
// Note: result will be true if the access token was received successfully
bool result = await credential.RequestAccessTokenAsync (cancel.Token);
// use the access token as the password string
client.Authenticate ("user#gmail.com", credential.Token.AccessToken);
// ...
client.Disconnect (true);
}

Categories