I added Service Account to my email@gmail.com, activated OAuth2 for it and downloaded the key. Then I followed the steps described in this (life saving) post with the only difference that I instantiated "credential" from Json file (loading p12 would always give me "Invalid network password"). With this I can successfully get Access Token, here is the line which does it:
Task<bool> result = credential.RequestAccessTokenAsync(CancellationToken.None);
Then I instantiate SmtpClient from MailKit and try to connect and authenticate:
client.Connect("smtp.gmail.com", 587, SecureSocketOptions.StartTls);
var oauth2 = new SaslMechanismOAuth2("email@gmail.com", credential.Token.AccessToken);
client.Authenticate(oauth2);
The last line generates exception that reads 555: 5.5.2 Syntax error, goodbye. l13sm3080685qtv.82 - gsmtp. The part that ends with .82 changes with each subsequent call. As per this post, I tried different variants for "email@gmail.com" (i.e. <email@gmail.com>). I also tried to use the Service Account email instead (the one similar to this: appName@serviceName.iam.gserviceaccount.com) but to no avail. I mad sure I am using latest versions of MailKit, MimeKit and Google.Api* and searched extensively but found nothing that could provide a solution.
Interestingly, without any change to the code I started experiencing different exception. It now comes partially base64 ecoded and reads this (after decoding): 334: {"status":"400","schemes":"Bearer","scope":"https://mail.google.com/"}
In the meantime I tried 2 other implementations that claim they got it right. None works - they all succeed with getting access token but break on "authenticate". All of that blows once's mind and makes the effort even more hopeless. One wonders if there is any C# code that is truly successful in sending gmail message using OAuth2... Any hint or other form of help would be greatly appreciated.
The method pointed by jstedfast below works well but I'd like to follow up with few issues. Too much for standard comment, so I added it here:
When the flow is executed for the first time, it opens popup browser window and user must login/approve the application/service to access gmail account. It loooks like access key must be stored on the hard drive. If I removed "DataStore" from GoogleAuthorizationCodeFlow constructor, the browser seems to popup each time when executing the code. The app I have to fix normally runs without any user interaction. Is there a way to avoid browser popup by enabling/disabling something in gmail account or service/app defined in developer's console? If standard gmail account cannot be used this way, perhaps email that is a part of GSuite domain can? The customer who owns the application uses Google GSuite and they have their domain with emails and documents. I think that now I understand jstedfast's remark on client-to-server vs server-to-server.