You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 17:53:16