使用ImapFlow读取Gmail收件箱时提示‘Invalid credentials (Failure)’错误
问题描述
我尝试用NodeJS读取Gmail收件箱,已创建Gmail账号并在Google Cloud配置OAuth应用,拿到了ClientID、ClientSecret和refresh token,但运行脚本时出现认证失败错误。
我的脚本
import xoauth2 from 'xoauth2'; import { ImapFlow } from 'imapflow'; const xoauth2Gen = xoauth2.createXOAuth2Generator({ user: 'MY_EMAIL@gmail.com', clientId: 'XXXXXXX.apps.googleusercontent.com', clientSecret: 'XXXX', refreshToken: 'XXXXXXX', }); const PreTestsAuthentication = async () => { const xoauth2Token = await new Promise<string>((resolve, reject) => { xoauth2Gen.getToken((error: unknown, token: string) => { if (error) { return reject(error); } return resolve(token); }); }); const client = new ImapFlow({ host: 'imap.gmail.com', port: 993, secure: true, auth: { user: 'MY_EMAIL@gmail.com', pass: 'XXXXX', accessToken: xoauth2Token, }, }); await client.connect(); await client.logout(); }; export default PreTestsAuthentication;
错误信息
{ "response": "3 NO [AUTHENTICATIONFAILED] Invalid credentials (Failure)", "responseStatus": "NO", "responseText": "Invalid credentials (Failure)", "serverResponseCode": "AUTHENTICATIONFAILED", "authenticationFailed": true, "oauthError": { "status": "invalid_request", "scope": "https://mail.google.com/" } }
refresh token获取方式
- 遵循Drive API快速开始指南获取refresh token
- 使用的代码:
const client = await authenticate({ scopes: ['https://www.googleapis.com/auth/drive.metadata.readonly'], keyfilePath: CREDENTIALS_PATH, });
从client对象提取refresh_token用于上述脚本。
解决方案
1. 核心问题:Scope不匹配
你获取refresh token时用的是Drive只读权限的scope,但访问Gmail IMAP必须使用Gmail相关权限,需包含https://mail.google.com/(IMAP访问所需的完整权限),或更窄的https://www.googleapis.com/auth/gmail.readonly(仅读取需求时可用)。
需重新获取带有Gmail scope的refresh token:
- 修改认证代码的scopes:
const client = await authenticate({ scopes: ['https://mail.google.com/'], keyfilePath: CREDENTIALS_PATH, });
- 重新运行认证流程,替换原refresh token(旧token因权限范围不匹配,无法用于Gmail认证)。
2. 修正ImapFlow的Auth配置
代码中同时传入pass和accessToken会导致冲突,OAuth认证无需密码,仅保留user和accessToken即可。
3. 改用官方Google Auth库(推荐)
xoauth2库维护活跃度低,建议使用官方google-auth-library生成access token,兼容性更有保障。
修正后的代码
import { ImapFlow } from 'imapflow'; import { OAuth2Client } from 'google-auth-library'; const oauth2Client = new OAuth2Client({ clientId: 'XXXXXXX.apps.googleusercontent.com', clientSecret: 'XXXX', refreshToken: '新获取的带Gmail scope的refreshToken', }); const PreTestsAuthentication = async () => { // 获取access token const { token } = await oauth2Client.getAccessToken(); if (!token) { throw new Error('Failed to get access token'); } const client = new ImapFlow({ host: 'imap.gmail.com', port: 993, secure: true, auth: { user: 'MY_EMAIL@gmail.com', accessToken: token, }, }); try { await client.connect(); console.log('Authentication successful!'); } catch (err) { console.error('Authentication failed:', err); } finally { await client.logout(); } }; export default PreTestsAuthentication;
额外注意事项
- 确保Google Cloud OAuth应用的授权域名、重定向URI配置正确(本地测试常用
http://localhost:3000)。 - Gmail账号需开启IMAP访问:设置→转发和POP/IMAP→IMAP访问→启用IMAP。
- Google Workspace账号需管理员允许该OAuth应用的权限。
内容的提问来源于stack exchange,提问作者Tal Rofe
相关产品推荐
相关产品推荐

