Javamail gmail 和 OAuth2
我正在尝试在 Web 应用程序 (java 1.8/tomcat8) 中使用最新的 javamail 1.6.0 api 来代表应用程序的客户端用户发送电子邮件.一些客户使用 gmail.我不想让他们按照 javamail 的建议在他们的谷歌帐户中启用对不安全应用程序的访问权限常见问题解答,如果需要,我愿意实施 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. Some clients use 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.
为此,我在 google 开发者控制台上执行了以下操作:
To do that, I did the following on google developer console:
- 创建了一个应用程序
- 为应用创建了 oauth2 凭据(clientid、客户机密)
- 授予应用访问 gmail api 的权限
然后,我使用 在我的应用中实现了 oauth2 流程谷歌 oauth 客户端
授权重定向构造:
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();
(其中code是返回的授权码)这似乎有效,并返回访问令牌和刷新令牌.(我也可以回到我的谷歌账户设置,看看我已经授权该应用发送电子邮件了.
(where code is the returned authorization code) This seems to work, and returns an access token and refresh token. (I can also go back to my google account settings and see that I have authorized the app to send email.
所以现在我想尝试使用访问令牌通过 javamail api 使用我的 gmail 用户名(我为授权应用程序而登录的用户名)、访问令牌和以下设置发送邮件:
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:
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 流
The javamail code works fine for other smtp servers. I also turned on debug to trace the smtp flow
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 状态,我将其解释为令牌无效.
decoding that last line I see that the error is a 400 status, that I interpret to mean that the token is not valid.
我还使用 google rest api 验证了令牌是好的:
I also verified that the token is good using the google rest api:
https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=<token>
我也尝试使用启用 ssl 的端口 465,但得到了同样的错误.
I also tried using port 465 with ssl enabled, but got the same error.
我在这里做错了什么?
推荐答案
这是对user2000974答案的补充.Google 关于使用 OAuth 对 IMAP 或 SMTP 服务器进行身份验证的文档 Gmail > IMAP > OAuth2.0机制明确说明如下
This is an addition to the answer of 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
本文档定义了与 IMAP AUTHENTICATE 和 SMTP AUTH 命令一起使用的 SASL XOAUTH2 机制.此机制允许使用 OAuth 2.0 访问令牌对用户的 Gmail 帐户进行身份验证.
This document defines the SASL XOAUTH2 mechanism for use with the IMAP AUTHENTICATE and SMTP AUTH commands. This mechanism allows the use of OAuth 2.0 Access Tokens to authenticate to a user's Gmail account.
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.
相关文章