【问题标题】:Javamail gmail and OAuth2Javamail gmail 和 OAuth2
【发布时间】:2017-08-07 15:17:16
【问题描述】:

我正在尝试在 Web 应用程序 (java 1.8/tomcat8) 中使用最新的 javamail 1.6.0 api 来代表应用程序的客户端用户发送电子邮件。一些客户使用 gmail。 我不想让他们按照javamail FAQ 的建议在他们的谷歌帐户中启用对不安全应用程序的访问,如果需要的话,我愿意实施 oauth2。

为此,我在google developer console 上执行了以下操作:

  • 创建了一个应用
  • 为应用程序创建了 oauth2 凭据(clientid, 客户机密)
  • 授予应用访问 gmail api 的权限

然后,我使用 google oauth client 在我的应用中实现了 oauth2 流程

授权重定向构造:

String url = 
        new GoogleAuthorizationCodeRequestUrl(clientId, 
            redirectUrl, 
            Collections.singleton(GmailScopes.GMAIL_SEND)
            ).setAccessType("offline").build();

这成功重定向到谷歌网站,我可以在该网站上验证和授权我的应用代表我发送邮件。我授权后成功重定向回我的应用,应用处理授权码:

GoogleTokenResponse response =
                new GoogleAuthorizationCodeTokenRequest(
                        new NetHttpTransport(), 
                        new JacksonFactory(),
                      clientId, 
                      clientSecret,
                      code, 
                      redirectUrl)
                .execute();

(其中code是返回的授权码) 这似乎有效,并返回访问令牌和刷新令牌。 (我也可以回到我的谷歌账户设置,看看我已经授权该应用发送电子邮件了。

所以现在我想尝试使用访问令牌通过 javamail api 使用我的 gmail 用户名(我为授权应用程序而登录的用户名)、访问令牌和以下设置发送邮件:

host = "smtp.gmail.com";
port = 587;
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.auth.mechanisms", "XOAUTH2");

javamail 代码适用于其他 smtp 服务器。 我还打开了调试来跟踪 smtp 流

DEBUG: JavaMail version 1.6.0
DEBUG: successfully loaded resource: /META-INF/javamail.default.providers
DEBUG: Tables of loaded providers
DEBUG: Providers Listed By Class Name: {com.sun.mail.smtp.SMTPSSLTransport=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], com.sun.mail.smtp.SMTPTransport=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle], com.sun.mail.imap.IMAPSSLStore=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], com.sun.mail.pop3.POP3SSLStore=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], com.sun.mail.imap.IMAPStore=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], com.sun.mail.pop3.POP3Store=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle]}
DEBUG: Providers Listed By Protocol: {imaps=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], imap=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], smtps=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], pop3=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle], pop3s=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], smtp=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]}
DEBUG: successfully loaded resource: /META-INF/javamail.default.address.map
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: trying to connect to host "smtp.gmail.com", port 587, isSSL false
220 smtp.gmail.com ESMTP c7sm3632131pfg.29 - gsmtp
DEBUG SMTP: connected to host "smtp.gmail.com", port: 587

EHLO 10.0.0.5
250-smtp.gmail.com at your service, [216.165.225.194]
250-SIZE 35882577
250-8BITMIME
250-STARTTLS
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 "STARTTLS", arg ""
DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg ""
DEBUG SMTP: Found extension "PIPELINING", arg ""
DEBUG SMTP: Found extension "CHUNKING", arg ""
DEBUG SMTP: Found extension "SMTPUTF8", arg ""
STARTTLS
220 2.0.0 Ready to start TLS
EHLO 10.0.0.5
250-smtp.gmail.com at your service, [216.165.225.194]
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 ""
DEBUG SMTP: protocolConnect login, host=smtp.gmail.com, user=<myemail@gmail.com>, password=<non-null>
DEBUG SMTP: Attempt to authenticate using mechanisms: XOAUTH2
DEBUG SMTP: Using mechanism XOAUTH2
DEBUG SMTP: AUTH XOAUTH2 command trace suppressed
DEBUG SMTP: AUTH XOAUTH2 failed, THROW: 


 javax.mail.AuthenticationFailedException: OAUTH2 asked for more
...
DEBUG SMTP: AUTH XOAUTH2 failed
ERROR 2017-08-06 18:39:57,443  - send: 334 eyJzdGF0dXMiOiI0MDAiLCJzY2hlbWVzIjoiQmVhcmVyIiwic2NvcGUiOiJodHRwczovL21haWwuZ29vZ2xlLmNvbS8ifQ==

解码最后一行我看到错误是 400 状态,我将其解释为令牌无效。

我还使用 google rest api 验证了令牌是好的:

https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=<token>

我也尝试使用启用 ssl 的端口 465,但得到了同样的错误。

我在这里做错了什么?

【问题讨论】:

  • 您是否尝试重新生成令牌?
  • 您将访问令牌而不是刷新令牌作为密码传递给 JavaMail API,对吗?而且在传递令牌之前,您不会以任何方式对令牌进行编码,对吗?令牌应少于 80 个字符,并且类似于“ya29.3QEMCT...”。您可能希望将 mail.debug.auth 属性设置为 true,以便您可以在调试输出中查看身份验证交换的详细信息,以防服务器提供更多在正常调试输出中被抑制的错误的详细信息。您可以将 Thunderbird 配置为在您的帐户中使用 OAUTH2 吗?
  • 是的,尝试使用最初生成的身份验证令牌,并尝试刷新它。我确实启用了 mail.debug.auth。没有看到更多的输出。
  • 啊!我的访问令牌以“ya29.GlugBAd...”开头,但长度为 132 个字符,看起来不同的实例的长度略有不同。我正在使用直接来自 GoogleResponse 的字符串,没有其他编码:String at=response.getAccessToken();
  • ...但是如上所述,我还通过 googleapis tokeninfo 方法运行了该令牌,它解析了该令牌以报告该范围适用于 gmail.send,它将在未来到期,并且它是一个“离线”令牌。

标签: java gmail jakarta-mail google-oauth


【解决方案1】:

这是对 user2000974 答案的补充。 Google 关于使用 OAuth 对 IMAP 或 SMTP 服务器进行身份验证的文档Gmail > IMAP > OAuth 2.0 Mechanism 明确说明了以下内容

本文档定义了用于 IMAP AUTHENTICATE 和 SMTP AUTH 命令的 SASL XOAUTH2 机制。此机制允许使用 OAuth 2.0 访问令牌对用户的 Gmail 帐户进行身份验证。

IMAP 和 SMTP 访问范围是https://mail.google.com/

我希望这会将将来偶然发现此问题的人们引导到正确的文档页面。

【讨论】:

  • 感谢您的链接!我搜索了三天的文档,但从未想过在 IMAP 文档中查看有关如何访问 SMTP 的信息。我之前引用的描述所有 google oauth2 范围的页面没有提到这一点。\
  • 感谢为我工作,印刷精美的警告很容易被忽略。除了在一个文档中说您应该尽可能使用受限权限,在我的情况下,我只需要发送权限,但对于 SMTP,仅发送是不够的。
【解决方案2】:

我尝试使用请求的范围,最后通过请求对 gmail 帐户的完全访问权限(范围 =“https://mail.google.com/”)使其工作。有限的documentation of the scopes 表明发送邮件的特定范围应该有效,但显然它没有。请求对帐户的完全访问权限是可行的,但似乎违背了限制范围的目的。它开始听起来像是 SMTP 服务器不尊重有限的范围。

【讨论】:

  • gmail.send 仅允许通过 Gmail API 发送电子邮件,用于 SMTP 发送 - 您需要请求完整的 Gmail 访问权限 - mail.google.com
  • 什么是 Gmail API?为什么它需要与 JavaMail 不同的范围?
猜你喜欢
  • 2011-09-21
  • 2022-08-14
  • 2010-12-06
  • 1970-01-01
  • 2016-03-22
  • 1970-01-01
  • 2014-03-06
  • 2013-01-26
  • 1970-01-01
相关资源
最近更新 更多