仅用用户名和密码能否通过Gmail API发邮件?附报错求助
关于用用户名密码通过Gmail API/SMTP发送邮件的问题
首先明确两个核心点:
- Gmail API本身完全不支持仅用用户名密码认证:它基于OAuth 2.0协议构建,必须使用客户端ID/密钥、服务账户凭证这类OAuth相关信息来获取访问令牌,不存在直接用用户名密码构建Gmail实例的方式。
- 你测试的是SMTP协议发邮件(不是Gmail API),但现在Google几乎全面禁用了普通用户名密码的SMTP登录,这就是你遇到
AuthenticationFailedException的直接原因。
为什么你的SMTP代码报错?
Google早在几年前就默认关闭了“不太安全的应用”的访问权限,不管是个人账户还是企业Workspace账户,直接用账户原密码通过SMTP登录都会被拒绝,报错里的535-5.7.8就是这个安全限制的提示。
可行的解决办法
1. SMTP方式:改用应用专用密码(仅适用于开启两步验证的账户)
如果你的账户已经开启了两步验证,可以创建一个应用专用密码来替换代码里的普通密码:
- 个人账户:在Google账户设置的“安全”板块找到“应用专用密码”,生成一个专门用于邮件客户端的密码
- 企业Workspace账户:需要管理员允许该账户创建应用专用密码,或者在管理控制台开启相关权限
把代码里的password替换成生成的应用专用密码后,原有SMTP代码就能正常工作。
2. 改用Gmail API(推荐,更安全合规)
既然你最初想使用Gmail API,这里给你一个适合企业Workspace账户的服务账户示例(支持域范围授权,无需用户手动授权):
首先要在Google Cloud控制台创建服务账户,下载JSON密钥文件,然后让Workspace管理员给这个服务账户授予Gmail API的域范围权限(比如https://www.googleapis.com/auth/gmail.send)。
然后用Kotlin实现发送邮件:
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport import com.google.api.client.json.gson.GsonFactory import com.google.api.services.gmail.Gmail import com.google.api.services.gmail.GmailScopes import com.google.api.services.gmail.model.Message import com.google.auth.http.HttpCredentialsAdapter import com.google.auth.oauth2.GoogleCredentials import java.io.ByteArrayOutputStream import java.io.FileInputStream import javax.mail.Session import javax.mail.internet.InternetAddress import javax.mail.internet.MimeMessage @Test fun sendMailViaGmailAPI() { // 加载服务账户密钥文件 val credentials = GoogleCredentials.fromStream(FileInputStream("service-account-key.json")) .createScoped(listOf(GmailScopes.GMAIL_SEND)) // 域范围授权,替换为你的企业邮箱账户 .createDelegated("your-enterprise-account@your-domain.com") // 构建Gmail API实例 val gmail = Gmail.Builder( GoogleNetHttpTransport.newTrustedTransport(), GsonFactory.getDefaultInstance(), HttpCredentialsAdapter(credentials) ).setApplicationName("Your App Name").build() // 创建MIME格式邮件 val session = Session.getDefaultInstance(Properties()) val mimeMessage = MimeMessage(session).apply { setFrom(InternetAddress("your-enterprise-account@your-domain.com")) setRecipients(javax.mail.Message.RecipientType.TO, InternetAddress.parse("recipient@example.com")) subject = "Testing Gmail API" setText("Hello from Gmail API!") } // 转换为Gmail API要求的Message格式 val baos = ByteArrayOutputStream() mimeMessage.writeTo(baos) val message = Message().setRaw( java.util.Base64.getUrlEncoder().encodeToString(baos.toByteArray()) ) // 发送邮件 gmail.users().messages().send("me", message).execute() println("Mail sent successfully via Gmail API!") }
总结
- 别再尝试用普通用户名密码调用Gmail API,这是不可能实现的,必须依赖OAuth 2.0相关凭证
- SMTP方式现在只能通过应用专用密码(需开启两步验证)或OAuth 2.0认证来使用
- 企业账户优先推荐Gmail API + 服务账户域范围授权的方案,无需用户交互,更适合自动化场景
内容的提问来源于stack exchange,提问作者Glory to Russia




