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

React结合Gmail API获取只读邮件遇403:权限配置与代码求助

解决Gmail API 403禁止访问问题(React + @react-oauth/google)

一、Google Cloud控制台权限配置

要访问Gmail API,必须先在Google Cloud控制台完成以下配置:

  • 启用Gmail API:进入Google Cloud控制台,搜索「Gmail API」,点击启用按钮。
  • 配置OAuth同意屏幕:
    1. 进入「OAuth同意屏幕」页面,选择外部类型(测试阶段)。
    2. 填写应用名称、支持邮箱等基础信息后,进入「范围」配置环节。
    3. 添加以下权限范围:
      • https://www.googleapis.com/auth/userinfo.profile(获取用户基本信息)
      • https://www.googleapis.com/auth/userinfo.email(获取用户邮箱)
      • https://www.googleapis.com/auth/gmail.readonly(只读访问Gmail邮件)
    4. 在「测试用户」列表中添加你要测试的邮箱账号(未发布的应用只能让测试用户登录)。
  • 确认OAuth客户端ID配置:检查你的Web应用客户端ID,确保授权重定向URI和本地开发地址一致(比如http://localhost:3000)。

二、代码修正

核心问题是登录时没有请求Gmail API的访问权限,需要调整useGoogleLogin的配置,并优化邮件获取逻辑:

修正后的完整代码

import React, { useState, useEffect } from 'react'
import {
  googleLogout,
  useGoogleLogin,
  TokenResponse,
} from '@react-oauth/google'
import axios from 'axios'

interface UserProfile {
  picture: string
  name: string
  email: string
}

interface GmailMessage {
  id: string
  threadId: string
}

const GoogleAuth: React.FC = () => {
  const [user, setUser] = useState<TokenResponse | null>(null)
  const [profile, setProfile] = useState<UserProfile | null>(null)
  const [inboxMessages, setInboxMessages] = useState<GmailMessage[]>([])

  // 登录时指定所需权限范围
  const login = useGoogleLogin({
    scope: 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/gmail.readonly',
    onSuccess: (tokenResponse) => setUser(tokenResponse),
    onError: (error) => console.log('登录失败:', error),
  })

  useEffect(() => {
    if (user) {
      // 获取用户基础信息
      axios
        .get('https://www.googleapis.com/oauth2/v1/userinfo', {
          headers: {
            Authorization: `Bearer ${user.access_token}`,
          },
        })
        .then((res) => setProfile(res.data))
        .catch((err) => console.log(err))

      // 获取收件箱邮件列表
      fetchInboxMessages(user.access_token)
    }
  }, [user])

  const logOut = () => {
    googleLogout()
    setProfile(null)
    setInboxMessages([])
  }

  // 获取收件箱邮件(带分页参数,避免返回过多数据)
  const fetchInboxMessages = async (accessToken: string) => {
    try {
      const response = await axios.get(
        'https://www.googleapis.com/gmail/v1/users/me/messages',
        {
          headers: {
            Authorization: `Bearer ${accessToken}`,
          },
          params: {
            maxResults: 10, // 只返回最新10封邮件
            labelIds: 'INBOX' // 限定只获取收件箱邮件
          }
        },
      )
      setInboxMessages(response.data.messages || [])
      console.log('收件箱邮件:', response.data)
    } catch (error) {
      console.error('获取邮件失败:', error)
    }
  }

  // 可选:获取单封邮件的详细内容
  const fetchMessageDetail = async (messageId: string, accessToken: string) => {
    try {
      const response = await axios.get(
        `https://www.googleapis.com/gmail/v1/users/me/messages/${messageId}`,
        {
          headers: {
            Authorization: `Bearer ${accessToken}`,
            params: {
              format: 'full' // 获取完整邮件内容,可选raw/minimal/full
            }
          }
        }
      )
      console.log('邮件详情:', response.data)
    } catch (error) {
      console.error('获取邮件详情失败:', error)
    }
  }

  return (
    <div style={{ padding: '20px' }}>
      {profile ? (
        <div>
          <img src={profile.picture} alt="用户头像" style={{ borderRadius: '50%', width: '80px' }} />
          <h3>已登录用户</h3>
          <p>姓名: {profile.name}</p>
          <p>邮箱: {profile.email}</p>
          <button onClick={logOut} style={{ margin: '10px 0' }}>退出登录</button>

          <h4>收件箱邮件列表</h4>
          {inboxMessages.length > 0 ? (
            <ul>
              {inboxMessages.map(msg => (
                <li key={msg.id} onClick={() => fetchMessageDetail(msg.id, user!.access_token)} style={{ cursor: 'pointer', padding: '8px', borderBottom: '1px solid #eee' }}>
                  邮件ID: {msg.id}
                </li>
              ))}
            </ul>
          ) : (
            <p>暂无邮件数据</p>
          )}
        </div>
      ) : (
        <button onClick={() => login()}>使用Google登录 🚀 </button>
      )}
    </div>
  )
}

export default GoogleAuth

关键修改点

  1. 添加权限范围:在useGoogleLogin中新增scope参数,明确请求Gmail只读权限,这是解决403错误的核心。
  2. 优化API请求:获取邮件时添加maxResults和labelIds参数,减少返回数据量并限定范围。
  3. 新增邮件详情获取函数:可选功能,用于查看单封邮件的具体内容。

注意事项

  • 如果仍出现403错误,检查测试用户是否正确添加,或者清除浏览器的OAuth缓存(可以通过浏览器设置移除相关应用授权)。
  • 正式发布应用前,需要将OAuth同意屏幕从测试模式切换到生产模式,并通过Google的审核。

内容的提问来源于stack exchange,提问作者Naveen Singh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 12:22:15