I would like to learn how to send emails using Mailkit. The problem is that I now use 2-factor authentication in my gmail account, so I can not use simplified mail sending options. According to Mailkit documentation - Oath needs to be used.
So I registered a new application in Google API and got the secret key. Then I try to authenticate like this:
var secrets = new ClientSecrets
{
ClientId = "xxxx",
ClientSecret = "yyyy"
};
var scopes = new string[] { GmailService.Scope.MailGoogleCom };
var googleCredentials = await GoogleWebAuthorizationBroker.AuthorizeAsync(secrets, scopes, email, CancellationToken.None);
if (googleCredentials.Token.IsExpired(SystemClock.Default))
{
await googleCredentials.RefreshTokenAsync(CancellationToken.None);
}
Upon reaching the AuthorizeAsync
line - a new browser window is opened where I have to enter my credentials.. This wouldn't be a problem if I were to run this application on Windows.. BUT, this is a huge problem.
I am building a console dotnet core application, which is meant to run in a Linux environment, in a CLI mode. I can't afford to ask to enter credentials each time token is expired.. because there is no GUI at all...
Is there a way I can make email sending "just" work without additional logins in external apps?
It has just occurred to me, that maybe it will be easier to register a new email account with simplified login option and use it in my apps instead of trying to make current Gmail account work.. So, any ideas or suggestions?
You can use a service account [1] [2] with domain wide delegation [3], which will grant you access to impersonate any gmail account from your domain. You can create a service account on Cloud Platform after selecting a project.
After you get the service account, you can create a p12 file which you can use to obtain the token you need to send emails on Mailkit. Here is the code explained in the Mailkit documentation to implement the use of service account [4]:
var certificate = new X509Certificate2 (@"C:\path\to\certificate.p12", "password", X509KeyStorageFlags.Exportable);
var credential = new ServiceAccountCredential (new ServiceAccountCredential
.Initializer ("[email protected]") {
// Note: other scopes can be found here: https://developers.google.com/gmail/api/auth/scopes
Scopes = new[] { "https://mail.google.com/" },
User = "[email protected]"
}.FromCertificate (certificate));
bool result = await credential.RequestAccessTokenAsync (CancellationToken.None);
// Note: result will be true if the access token was received successfully
using (var client = new ImapClient ()) {
client.Connect ("imap.gmail.com", 993, true);
var oauth2 = new SaslMechanismOAuth2 ("[email protected]", credential.Token.AccessToken);
client.Authenticate (oauth2);
}
The path string on the first function of the code is the file path to the p12 file from your service account, which you can download from Cloud Platform.
Edit:
A workaround if you are not a G Suite administrator, would be implement the authorization flow as it’s in the quickstart [5], this will prompt you the consent screen on the browser only the first time you run it and it’ll create a token, which you can use in the subsequent runs of the code by leaving the token file inside the working directory. You would have to check how to use the gmail service or credentials object in the MailKit library.
[1] https://cloud.google.com/iam/docs/service-accounts
[2] https://cloud.google.com/iam/docs/understanding-service-accounts
[3] https://developers.google.com/admin-sdk/directory/v1/guides/delegation
[5] https://developers.google.com/gmail/api/quickstart/dotnet