Google Workspace用户邮箱使用报告代码HttpError 400报错排查
执行Python代码调用Google Admin Directory API获取用户邮箱信息时,在users = service.users().list().execute()处抛出400错误:
HttpError 400 when requesting https://admin.googleapis.com/admin/directory/v1/users?alt=json returned "Bad Request". Details: "[{'message': 'Bad Request', 'domain': 'global', 'reason': 'badRequest'}]"
完整代码如下:
from __future__ import print_function import os.path import csv import io from google.auth.transport.requests import Request from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import InstalledAppFlow from googleapiclient.discovery import build # If modifying these scopes, delete the file token.json. #SCOPES = ['https://www.googleapis.com/auth/admin.directory.user.readonly'] SCOPES = ['https://admin.googleapis.com/admin/directory/v1/users'] creds = None # The file token.json stores the user's access and refresh tokens, and is # created automatically when the authorization flow completes for the first # time. if os.path.exists('token.json'): creds = Credentials.from_authorized_user_file('token.json', SCOPES) # If there are no (valid) credentials available, let the user log in. if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( 'credentials.json', SCOPES) creds = flow.run_local_server(port=0) # Save the credentials for the next run with open('token.json', 'w') as token: token.write(creds.to_json()) service = build('admin', 'directory_v1', credentials=creds) print('Getting users in the domain') users = service.users().list().execute() # Create a dictionary to store the user data. user_data = {} # Iterate over the list of users and get their first name, last name, and mailbox size. for user in users[\"users\"]: user_data[user[\"primaryEmail\"]] = { \"firstName\": user[\"name\"][\"givenName\"], \"lastName\": user[\"name\"][\"familyName\"], \"mailboxSize\": user[\"storage\"][\"quotaUsage\"], } # Open the CSV file for writing. with open(\"user_data.csv\", \"w\", newline=\"\") as f: writer = csv.writer(f) # Write the header row. writer.writerow([\"email\", \"firstName\", \"lastName\", \"mailboxSize\"]) # Iterate over the user data and write each user's data to a new row in the CSV file. for email, data in user_data.items(): writer.writerow([email, data[\"firstName\"], data[\"lastName\"], data[\"mailboxSize\"]]) # Close the CSV file. f.close()
已确认凭证正确,尝试过不同Scope,询问操作错误点。
权限范围错误:你用的
https://admin.googleapis.com/admin/directory/v1/users不是合法的API权限范围,应使用https://www.googleapis.com/auth/admin.directory.user.readonly(只读权限足够)。修改后必须删除本地的token.json文件,重新授权生成新凭证。缺少必填参数:
users.list()方法必须指定customer或domain参数才能调用成功。如果是G Suite管理员,用customer='my_customer';如果指定域名,用domain='你的域名.com'。示例:users = service.users().list(customer='my_customer').execute()邮箱容量字段获取方式错误:Directory API的
users.list接口默认只返回用户基础信息(如邮箱、姓名),不会包含storage字段。要获取邮箱容量,需对每个用户调用users.get方法,并指定projection='full'参数,示例:user_detail = service.users().get(userKey=user['primaryEmail'], projection='full').execute() mailbox_size = user_detail.get('storage', {}).get('quotaUsage', 'N/A')代码缩进问题:原代码存在多处缩进错误(如
creds = None后的注释、if os.path.exists块的缩进),会导致Python解释器报错,需修正为正确的缩进格式。
from __future__ import print_function import os.path import csv from google.auth.transport.requests import Request from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import InstalledAppFlow from googleapiclient.discovery import build # 正确的只读权限范围,修改后请删除token.json重新授权 SCOPES = ['https://www.googleapis.com/auth/admin.directory.user.readonly'] creds = None # token.json存储用户的访问和刷新令牌,首次授权自动创建 if os.path.exists('token.json'): creds = Credentials.from_authorized_user_file('token.json', SCOPES) # 无有效凭证时重新登录授权 if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( 'credentials.json', SCOPES) creds = flow.run_local_server(port=0) # 保存凭证供下次使用 with open('token.json', 'w') as token: token.write(creds.to_json()) service = build('admin', 'directory_v1', credentials=creds) print('正在获取域内用户信息...') # 添加customer参数,my_customer代表当前管理员管理的所有用户 users_result = service.users().list(customer='my_customer', maxResults=500).execute() users = users_result.get('users', []) user_data = {} for user in users: # 调用get接口获取完整用户信息(包含storage字段) user_detail = service.users().get(userKey=user['primaryEmail'], projection='full').execute() user_data[user['primaryEmail']] = { 'firstName': user_detail['name']['givenName'], 'lastName': user_detail['name']['familyName'], 'mailboxSize': user_detail.get('storage', {}).get('quotaUsage', '无数据') } # 写入CSV文件 with open("user_data.csv", "w", newline="", encoding='utf-8') as f: writer = csv.writer(f) writer.writerow(["邮箱", "名", "姓", "邮箱容量"]) for email, data in user_data.items(): writer.writerow([email, data["firstName"], data["lastName"], data["mailboxSize"]]) print('数据已成功导出到user_data.csv')
内容的提问来源于stack exchange,提问作者Yuri

