简体   繁体   English

Javamail gmail 和 OAuth2

[英]Javamail gmail and OAuth2

I'm trying to use the latest javamail 1.6.0 api in a web app (java 1.8/tomcat8) to send email on behalf of client users of the app.我正在尝试在 web 应用程序(java 1.8/tomcat8)中使用最新的 javamail 1.6.0 api 代表客户端用户发送 email。 Some clients use gmail.一些客户使用 gmail。 I don't want to ask them to enable access to insecure apps in their google accounts as suggested by the javamail FAQ , and I'm willing to implement oauth2 if that's what it takes.我不想要求他们按照javamail FAQ的建议在他们的谷歌帐户中启用对不安全应用程序的访问,如果需要的话,我愿意实施 oauth2。

To do that, I did the following on google developer console :为此,我在谷歌开发者控制台上做了以下操作:

  • created an app创建了一个应用
  • created oauth2 credentials for the app (clientid, clientsecret)为应用程序创建了 oauth2 凭据(clientid、clientsecret)
  • granted the app access to gmail api授予应用程序访问 gmail api

Then, I implemented the oauth2 flow in my app using the google oauth client然后,我使用google oauth 客户端在我的应用程序中实现了 oauth2 流程

The authorization redirect is constructed:授权重定向的构造:

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

That successfully redirects to the google site where I can authenticate and authorize my app to send mail on my behalf.这成功地重定向到谷歌网站,我可以在其中验证和授权我的应用程序代表我发送邮件。 It successfully redirects back to my app after I authorize, and the app processes the authorization code:我授权后它成功重定向回我的应用程序,应用程序处理授权码:

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

(where code is the returned authorization code) This seems to work, and returns an access token and refresh token. (其中 code 是返回的授权代码)这似乎有效,并返回访问令牌和刷新令牌。 (I can also go back to my google account settings and see that I have authorized the app to send email. (我也可以将 go 返回到我的 google 帐户设置,并查看我已授权该应用发送 email。

So now I want to try to use the access token to send mail through the javamail api using my gmail username (the one I logged in as to authorize the app), the access token, and the following settings:所以现在我想尝试使用访问令牌通过 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");

The javamail code works fine for other smtp servers. javamail 代码适用于其他 smtp 服务器。 I also turned on debug to trace the smtp flow我还打开了调试以跟踪 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==

decoding that last line I see that the error is a 400 status, that I interpret to mean that the token is not valid.解码最后一行我看到错误是 400 状态,我解释为令牌无效。

I also verified that the token is good using the google rest api:我还使用谷歌 rest api 验证了令牌是否良好:

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

I also tried using port 465 with ssl enabled, but got the same error.我还尝试在启用 ssl 的情况下使用端口 465,但遇到了同样的错误。

what am I doing wrong here?我在这里做错了什么?

This is an addition to the answer of user2000974.这是对 user2000974 的回答的补充。 The documentation of Google about using OAuth to authenticate to an IMAP or SMTP server Gmail > IMAP > OAuth 2.0 Mechanism clearly states the following Google 关于使用 OAuth 对 IMAP 或 SMTP 服务器进行身份验证的文档Gmail > IMAP > OAuth 2.0 Mechanism明确指出以下内容

This document defines the SASL XOAUTH2 mechanism for use with the IMAP AUTHENTICATE and SMTP AUTH commands.本文档定义了与 IMAP AUTHENTICATE 和 SMTP AUTH 命令一起使用的 SASL XOAUTH2 机制。 This mechanism allows the use of OAuth 2.0 Access Tokens to authenticate to a user's Gmail account.此机制允许使用 OAuth 2.0 访问令牌对用户的 Gmail 帐户进行身份验证。

The scope for IMAP and SMTP access is https://mail.google.com/ . IMAP 和 SMTP 访问的范围是https://mail.google.com/

I hope this will direct people that stumble upon this question in the future to the right documentation page.我希望这会将将来偶然发现这个问题的人引导到正确的文档页面。

I tried playing with the requested scopes, and finally got it to work by requesting full access to the gmail account (scope = " https://mail.google.com/ ").我尝试使用请求的范围,最后通过请求对 gmail 帐户的完全访问权限(范围 =“ https://mail.google.com/ ”)使其工作。 The limited documentation of the scopes suggests that the specific scope for sending mail SHOULD work, but apparently it doesn't.范围的有限文档表明发送邮件的特定范围应该起作用,但显然它没有。 Requesting full access to the account works, but seems to defeat the purpose of having limited scopes.请求对帐户的完全访问权限有效,但似乎违背了限制范围的目的。 It's starting to sound like the SMTP server just isn't respecting the limited scope.它开始听起来像 SMTP 服务器只是不尊重有限的范围。

Something important, beware from Gmail API and Gmail IMAP, because they're not the same when this problem occurs.一些重要的事情,请注意 Gmail API 和 Gmail IMAP,因为发生此问题时它们并不相同。 Gmail API allows multiple and granular scopes to specific task, but when using Gmail IMAP it will require always the full scope. Gmail API 允许对特定任务进行多个细粒度范围,但是在使用 Gmail IMAP 时,它将始终需要完整的 Z31A1FD140BE4BEF2AEC9A8A。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM