使用OAuth2认证Gmail SMTP失败:555-5.5.2语法错误求助
Google SMTP OAuth2 认证遭遇555-5.5.2语法错误排查
因为Google即将取消SMTP的PLAIN认证支持,我打算迁移到OAuth2认证。按照官方文档创建了服务账号和JSON密钥后,写Java代码尝试认证时碰到了555-5.5.2语法错误,用curl测试也出现同样问题,错误出在认证阶段,不是邮件发送环节,求排查原因。
代码示例
import com.google.auth.oauth2.ServiceAccountCredentials; import com.sun.mail.smtp.SMTPTransport; import jakarta.mail.Session; import java.io.InputStream; import java.util.Base64; import java.util.Collections; import java.util.Properties; public class ForSendingEmailOauthAdapater { void send() throws Exception { InputStream secret = this.getClass().getClassLoader().getResourceAsStream("keys.json"); String email = "myemail@test.com"; // 生产环境为服务账号邮箱 GoogleCredentials credentials = ServiceAccountCredentials.fromStream(secret) .createScoped(Collections.singletonList("https://mail.google.com/")); credentials.refreshIfExpired(); String token = credentials .getAccessToken() .getTokenValue(); Properties props = new Properties(); props.put("mail.smtp", "true"); props.put("mail.transport.protocol", "smtp"); props.put("mail.smtp.auth.mechanisms", "XOAUTH2"); props.put("mail.smtp.starttls.enable", "true"); Session session = Session.getInstance(props); session.setDebug(true); SMTPTransport transport = (SMTPTransport) session.getTransport("smtp"); transport.connect("smtp.gmail.com", 587, email, null); String authString = "user=" + email + "\001auth=Bearer " + token + "\001\001"; String base64oauth2String = Base64.getEncoder().encodeToString(authString.getBytes()); transport.issueCommand("AUTH XOAUTH2 " + base64oauth2String, 235); } }
错误日志
STARTTLS 220 2.0.0 Ready to start TLS EHLO <myhostname> 250-smtp.gmail.com at your service, [89.64.21.109] 250-SIZE 35882577 250-8BITMIME 250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH 250-ENHANCEDSTATUSCODES 250-PIPELINING 250-CHUNKING 250 SMTPUTF8 DEBUG SMTP: Found extension "SIZE", arg "35882577" DEBUG SMTP: Found extension "8BITMIME", arg "" DEBUG SMTP: Found extension "AUTH", arg "LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH" DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg "" DEBUG SMTP: Found extension "PIPELINING", arg "" DEBUG SMTP: Found extension "CHUNKING", arg "" DEBUG SMTP: Found extension "SMTPUTF8", arg "" AUTH XOAUTH2 <base64 encoded user&token> 555-5.5.2 Syntax error, goodbye. For more information, go to 555-5.5.2 https://support.google.com/a/answer/3221692 and review RFC 5321 555 5.5.2 specifications. a640c23a62f3a-a725f5e1b52sm262436666b.135 - gsmtp
curl测试命令
curl -sv --url 'smtp://smtp.gmail.com:587' \ --ssl-reqd \ --login-options 'AUTH=XOAUTH2' --oauth2-bearer <access_token> \ --user <service account email> \ --mail-from test@test.com --mail-rcpt test@test.com
问题原因及解决办法
1. 服务账号使用限制
Google SMTP的XOAUTH2认证,普通服务账号无法直接用于Gmail个人邮箱,必须是Google Workspace(原G Suite)账号,并且要开启域范围委派,将服务账号模拟成域内用户。如果是个人Gmail账号,不能用服务账号做OAuth2认证SMTP,得用普通的OAuth2客户端ID(授权码模式)。
2. Java代码中的认证逻辑问题
你手动构造XOAUTH2认证字符串的方式有误,JavaMail其实已经内置了XOAUTH2的支持,不需要自己调用issueCommand,正确的做法是通过Authenticator或者直接传入token相关的认证信息:
修改后的代码示例:
import com.google.auth.oauth2.GoogleCredentials; import com.google.auth.oauth2.ServiceAccountCredentials; import jakarta.mail.*; import jakarta.mail.internet.InternetAddress; import jakarta.mail.internet.MimeMessage; import java.io.InputStream; import java.util.Collections; import java.util.Properties; public class ForSendingEmailOauthAdapater { void send() throws Exception { InputStream secret = this.getClass().getClassLoader().getResourceAsStream("keys.json"); // 注意:这里必须是Google Workspace域内的用户邮箱,不是服务账号邮箱 String userEmail = "actual-user@your-domain.com"; GoogleCredentials credentials = ServiceAccountCredentials.fromStream(secret) .createScoped(Collections.singletonList("https://mail.google.com/")) .createDelegated(userEmail); // 关键:模拟域内用户 credentials.refreshIfExpired(); String accessToken = credentials.getAccessToken().getTokenValue(); Properties props = new Properties(); props.put("mail.smtp.host", "smtp.gmail.com"); props.put("mail.smtp.port", "587"); props.put("mail.smtp.auth", "true"); props.put("mail.smtp.starttls.enable", "true"); props.put("mail.smtp.auth.mechanisms", "XOAUTH2"); Session session = Session.getInstance(props, new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(userEmail, accessToken); } }); session.setDebug(true); // 创建邮件 Message message = new MimeMessage(session); message.setFrom(new InternetAddress(userEmail)); message.setRecipients(Message.RecipientType.TO, InternetAddress.parse("recipient@example.com")); message.setSubject("Test Email via OAuth2"); message.setText("This is a test email sent using Google Workspace service account with OAuth2."); // 发送邮件 Transport.send(message); } }
3. curl测试的问题
同样,curl测试时如果是服务账号,需要确保是Google Workspace环境且已配置委派,并且--user参数应该是被模拟的域内用户邮箱,不是服务账号邮箱,同时确认access token是用服务账号模拟该用户生成的。
关键注意点
- 个人Gmail账号无法使用服务账号做SMTP OAuth2认证,只能用OAuth2客户端ID(需要用户授权获取刷新令牌)。
- Google Workspace账号需要在管理后台给服务账号开启域范围委派,并授予
https://mail.google.com/权限。 - JavaMail版本建议使用最新的Jakarta Mail(原JavaMail),确保对XOAUTH2的支持完善。
内容的提问来源于stack exchange,提问作者xmcax
相关产品推荐
相关产品推荐

