使用MailKit通过AccessToken认证Gmail SMTP时出现凭证无效错误
嘿,这个AuthenticationInvalidCredentials错误我之前也踩过坑!本质就是Google不认你的授权凭证,大概率是OAuth2的配置或者token本身出了问题,给你几个排查和解决的方向:
先确认OAuth2 Scope是否正确
要通过API发送Gmail,必须申请正确的权限范围。至少要选https://www.googleapis.com/auth/gmail.send(只允许发送邮件),或者更全的https://mail.google.com/(完全访问邮箱)。如果获取AccessToken时请求的Scope不对,哪怕token是有效的,Google也会直接拒绝你的邮件请求。检查AccessToken的有效性和刷新机制
Google的AccessToken有效期只有1小时,过期后必须用Refresh Token去刷新获取新的AccessToken。如果你的代码里没处理token过期的情况,用了过期的token,肯定会报这个错。建议在发送邮件前先判断token是否过期,过期就调用刷新接口换新的。确认你的Google Cloud应用配置没问题
如果是你自己在Google Cloud上创建的OAuth2应用,要注意这几点:- 应用至少要处于测试发布状态(不然只有你这个开发者账号能授权,其他账号用不了)
- 如果你用的是测试状态的应用,要把发送邮件的账号添加到测试用户列表里
- 如果用的是Service Account(服务账号),必须开启域范围委派,并且指定要模拟发送的用户邮箱(因为服务账号本身不能直接发邮件,得模拟域内用户)
补全正确的邮件发送代码逻辑
看你贴的代码片段只设置了From,没看到SmtpClient的认证部分,大概率是这里没配置对。给你一个完整的MimeKit+MailKit搭配OAuth2的示例,你可以对照着改:using MailKit.Net.Smtp; using MimeKit; using Google.Apis.Auth.OAuth2; using System.Threading; // 构建邮件内容 var msg = new MimeMessage(); msg.From.Add(new MailboxAddress(Name, Email)); msg.To.Add(new MailboxAddress("收件人名称", "recipient@example.com")); msg.Subject = "你的邮件主题"; msg.Body = new TextPart("html") { Text = "<p>这是邮件内容</p>" }; // 获取或刷新有效的AccessToken var credential = GoogleWebAuthorizationBroker.AuthorizeAsync( new ClientSecrets { ClientId = "你的ClientID", ClientSecret = "你的ClientSecret" }, new[] { "https://www.googleapis.com/auth/gmail.send" }, "user", CancellationToken.None).Result; // 检查token是否过期,过期则刷新 if (credential.Token.IsExpired(SystemClock.Default)) { if (!credential.RefreshTokenAsync(CancellationToken.None).Result) { throw new InvalidOperationException("无法刷新AccessToken,请检查Refresh Token是否有效"); } } // 发送邮件 using (var client = new SmtpClient()) { client.Connect("smtp.gmail.com", 587, MailKit.Security.SecureSocketOptions.StartTls); // 关键:用OAuth2机制认证,这里要传入你的邮箱和有效的AccessToken client.Authenticate(new SaslMechanismOAuth2(Email, credential.Token.AccessToken)); client.Send(msg); client.Disconnect(true); }别碰“不太安全的应用访问”(不推荐)
虽然以前可以通过开启这个选项用账号密码发邮件,但Google现在已经默认关闭了,而且这个方式非常不安全,所以优先用OAuth2的方案,别折腾这个了。
内容的提问来源于stack exchange,提问作者Naveen

