问题
I'm trying to use Mailkit to get emails from my Gmail:
private readonly string[] Scopes = { GmailService.Scope.GmailReadonly };
private UserCredential GetGmailCredential()
{
UserCredential credential;
using (var stream = new FileStream("client_id.json", FileMode.Open, FileAccess.Read))
{
// The file token.json stores the user's access and refresh tokens, and is created
// automatically when the authorization flow completes for the first time.
string credPath = "token.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true),
new LocalServerCodeReceiver()).Result;
Console.WriteLine($"Credential file saved to: {credPath}");
}
return credential;
}
[HttpGet("check")]
public string GetD()
{
using (var client = new ImapClient())
{
client.Connect("imap.gmail.com", 993, SecureSocketOptions.SslOnConnect);
UserCredential credential = GetGmailCredential();
//var oauth2 = new SaslMechanismOAuth2("myaccount008@gmail.com", credential.Token.AccessToken);
var oauth2 = new SaslMechanismOAuth2("myaccount008",credential.Token.AccessToken);
client.Authenticate(oauth2);
client.Inbox.Open(FolderAccess.ReadOnly);
var uids = client.Inbox.Search(SearchQuery.FromContains("bill"));
string subjects = string.Empty;
foreach (var uid in uids)
{
var message = client.Inbox.GetMessage(uid);
subjects += message.Subject + Environment.NewLine;
// write the message to a file
message.WriteTo(string.Format("{0}.eml", uid));
}
client.Disconnect(true);
return subjects;
}
}
Line: client.Authenticate(oauth2); throw exception ->
MailKit.Security.AuthenticationException
I followed this answer to setup my Gmail API, but then I got the Authentication Failed issue.
Update 1
Here is the log:
Connected to imaps://imap.gmail.com:993/ S: * OK Gimap ready for requests from 122.199.45.135 d3mb920463124pjs C: A00000000 CAPABILITY S: * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH2 AUTH=PLAIN AUTH=PLAIN-CLIENTTOKEN AUTH=OAUTHBEARER AUTH=XOAUTH S: A00000000 OK Thats all she wrote! d3mb920463124pjs C: A00000001 AUTHENTICATE XOAUTH2 dXNlcj1mcmFudmEwMDhAZ21haWwuY29tAWF1dGg9QmVhcmVyIHlhMjkuYTBBZHcxeGVWZDNSWWwzcVZlblZwVm1MbDBRRVVyWkdxd05veEd0QWpcLVhHNjRBaF90eWM0NWhwSFprZHA0d3dPWlpGMVZwbGM3dGo1Tm80eVMwc2lPNE1VYmhHV1I1WE9sdWtLUGY4TF9QU0dpZjhrSWM2UXNUbTQwYjlweDNBeXE4bVYtOTM2akEtSHdXekNQVFdGMGk0NGozX2FOTmhEYk5rAQE= S: + eyJzdGF0dXMiOiI0MDAiLCJzY2hlbWVzIjoPQmVhcmVyIiwic2NvcGUiOiJodHRwczovL21haWwuZ29vZ2xlLmNvbS8ifQ== C: S: A00000001 NO [AUTHENTICATIONFAILED] Invalid credentials (Failure)
The scope, I use: GmailService.Scope.GmailReadonly as I only need to retrieve emails.
Update 2
Updated my scope to:
private readonly string[] Scopes = { GmailService.Scope.MailGoogleCom };
Connected to imaps://imap.gmail.com:993/ S: * OK Gimap ready for requests from 122.199.45.135 s90mb321411106pjc C: A00000000 CAPABILITY. S: * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH2 AUTH=PLAIN AUTH=PLAIN-CLIENTTOKEN AUTH=OAUTHBEARER AUTH=XOAUTH S: A00000000 OK Thats all she wrote! s90mb321411106pjc C: A00000001 AUTHENTICATE XOAUTH2 dXNlcj1mcmFudmEwMDhAZ21haWwuY29tAWF1dGg9QmVhcmVyIHlhMjkuYTBBZHcxeGVWZDNSWWwzcVZlblZwVm1MbDBRRVVyWkdxd05veEd0QWpXLVhHNjRBaF90eWM0NWhwSFprZHA0d3dPWlpGMVZwbGM3dGo1Tm80eVMwc2lPNE1VYmhHV1I1WE9sdWtLUGY4TF9QU0dpZjhrSWM2UXNUbTQwYjlweDNBeXE4bVYtOTM2akEtSHdXekNQVFdGMGk0NGozX2FPTmhEYk5rAQE= S: + eyJzdGF0dXMiOiI0MDAiLCJzY2hlbWVzIjoiSmVhcmVyIiwic2NvcGUiOiJodHRwczovL21haWwuZ29vZ2xlLmNvbS8ifQ== C: S: A00000001 NO [AUTHENTICATIONFAILED] Invalid credentials (Failure)
Update 3
I keep everything same and also tried to use GmailService.Scope.ReadOnly then replaced ImapClient with the following code, now it works.
// Create Gmail API service.
service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
This piece of code is from the Gmail Api. It would be great if I could use Mailkit to do the authentication.
回答1:
Part of the problem is that you are using the wrong scope. You need to use GoogleService.Scope.MailGoogleCom.
The scope you are using is not for IMAP or POP3 access, it only works for Google’s web request API.
The following code works for me:
const string GMailAccount = "username@gmail.com";
var clientSecrets = new ClientSecrets {
ClientId = "XXX.apps.googleusercontent.com",
ClientSecret = "XXX"
};
var codeFlow = new GoogleAuthorizationCodeFlow (new GoogleAuthorizationCodeFlow.Initializer {
DataStore = new FileDataStore ("CredentialCacheFolder", false),
Scopes = new [] { "https://mail.google.com/" },
ClientSecrets = clientSecrets
});
var codeReceiver = new LocalServerCodeReceiver ();
var authCode = new AuthorizationCodeInstalledApp (codeFlow, codeReceiver);
var credential = await authCode.AuthorizeAsync (GMailAccount, CancellationToken.None);
if (authCode.ShouldRequestAuthorizationCode (credential.Token))
await credential.RefreshTokenAsync (CancellationToken.None);
var oauth2 = new SaslMechanismOAuth2 (credential.UserId, credential.Token.AccessToken);
using (var client = new ImapClient ()) {
await client.ConnectAsync ("imap.gmail.com", 993, SecureSocketOptions.SslOnConnect);
await client.AuthenticateAsync (oauth2);
await client.DisconnectAsync (true);
}
来源:https://stackoverflow.com/questions/60708820/what-is-the-correct-way-to-authenticate-using-gmail-oauth2-0-in-mailkit