Conexión con Gmail mediante la API
Biblioteca cliente de Google API, consentimiento OAuth2 y selección de ámbitos de Gmail.
Conexión con Gmail mediante la API es una lección gratuita de AI Agents en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de AI Agents, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de AI Agents incluye 4 lecciones en total.
¿Por qué usar Gmail API en lugar de SMTP?
La automatización tradicional del correo electrónico usa SMTP/IMAP, pero la Gmail API ofrece mucho más: leer hilos, buscar mediante consultas, gestionar etiquetas y enviar con autenticación completa. También admite OAuth 2.0, por lo que su agente nunca almacena una contraseña, sino únicamente un token de acceso con un alcance limitado.
La Gmail API forma parte de las Google Workspace APIs y se accede a ella mediante la biblioteca google-api-python-client.
# Install required libraries:
# pip install google-api-python-client google-auth google-auth-oauthlib
# The Gmail API lets agents:
# - List and search messages (labels, queries)
# - Read full message content and attachments
# - Send messages via OAuth (no password needed)
# - Manage labels and threads
# - Watch for new messages via push notifications
print('Gmail API is part of Google Workspace APIs')Autenticación: cuenta de servicio frente a autenticación de usuario
Existen dos métodos de autenticación para la Gmail API:
- Cuenta de servicio: ideal para uso en espacios de trabajo u organizaciones con delegación en todo el dominio; no requiere interacción del usuario
- OAuth de usuario (OAuth2 con pantalla de consentimiento): necesario para cuentas personales de Gmail; el usuario concede acceso una vez y el agente usa un token de actualización
Para la mayoría de las automatizaciones con agentes, se prefieren las cuentas de servicio por su fiabilidad.
# Service Account approach:
# 1. Go to Google Cloud Console -> APIs & Services -> Credentials
# 2. Create a Service Account
# 3. Download the JSON key file
# 4. In Google Workspace Admin: enable domain-wide delegation
# 5. Grant required scopes to the service account
# User OAuth approach:
# 1. Create OAuth 2.0 Client ID (Desktop or Web App type)
# 2. Download credentials.json
# 3. First run: user sees consent screen and grants access
# 4. Agent stores token.json with refresh token for subsequent runs
print('Choose service account for org automation, OAuth for personal Gmail')Estructura JSON de las credenciales OAuth2
Google proporciona las credenciales en un archivo JSON que el agente carga para autenticarse. En el caso de OAuth de usuario, se trata de un archivo credentials.json descargado de Google Cloud Console. El archivo contiene el ID de cliente, el secreto y el URI de redirección; nunca lo incluya en el control de versiones.
# credentials.json structure (User OAuth — Desktop app type):
# {
# "installed": {
# "client_id": "123456789.apps.googleusercontent.com",
# "client_secret": "GOCSPX-abc123xyz",
# "redirect_uris": ["urn:ietf:wg:oauth:2.0:oob", "http://localhost"],
# "auth_uri": "https://accounts.google.com/o/oauth2/auth",
# "token_uri": "https://oauth2.googleapis.com/token"
# }
# }
# service-account.json structure:
# {
# "type": "service_account",
# "project_id": "my-project",
# "private_key_id": "abc123",
# "private_key": "-----BEGIN PRIVATE KEY-----\n...",
# "client_email": "agent@my-project.iam.gserviceaccount.com",
# "client_id": "..."
# }
print('Store credential files outside your git repository')Scopes de la Gmail API
Los scopes de OAuth definen exactamente a qué puede acceder su agente. Solicite únicamente los scopes que necesita: este es el principio de privilegio mínimo. Los scopes de Gmail van desde acceso de solo lectura hasta acceso completo.
gmail.readonly— leer todo el correogmail.send— solo enviar, sin leergmail.modify— leer, enviar y modificar etiquetasgmail.compose— crear únicamente borradores
# Gmail API scope constants
SCOPE_READONLY = 'https://www.googleapis.com/auth/gmail.readonly'
SCOPE_SEND = 'https://www.googleapis.com/auth/gmail.send'
SCOPE_MODIFY = 'https://www.googleapis.com/auth/gmail.modify'
SCOPE_COMPOSE = 'https://www.googleapis.com/auth/gmail.compose'
# Calendar scopes (often used alongside Gmail)
SCOPE_CALENDAR_READ = 'https://www.googleapis.com/auth/calendar.readonly'
SCOPE_CALENDAR_EVENTS = 'https://www.googleapis.com/auth/calendar.events'
# Combine scopes your agent actually needs
AGENT_SCOPES = [
SCOPE_READONLY,
SCOPE_SEND,
SCOPE_CALENDAR_EVENTS
]
print(f'Using {len(AGENT_SCOPES)} scopes')OAuth de usuario: flujo de autenticación inicial
La primera vez que un usuario ejecuta el agente, este abre un navegador para que el usuario conceda permiso. El agente guarda el token resultante en token.json. En ejecuciones posteriores, carga el token almacenado y lo actualiza automáticamente; no se necesita interactuar con el navegador.
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
import os
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
def get_credentials(token_file='token.json', creds_file='credentials.json'):
creds = None
# Load existing token if available
if os.path.exists(token_file):
creds = Credentials.from_authorized_user_file(token_file, SCOPES)
# Refresh or re-authenticate if needed
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request()) # auto-refresh
else:
# Opens browser for user consent (first time only)
flow = InstalledAppFlow.from_client_secrets_file(
creds_file, SCOPES
)
creds = flow.run_local_server(port=0)
# Save token for next run
with open(token_file, 'w') as f:
f.write(creds.to_json())
return credsAutenticación con una cuenta de servicio
Para los agentes automatizados que se ejecutan sin interacción del usuario, las cuentas de servicio son ideales. El agente se autentica con una clave privada y luego actúa en nombre de un usuario de Google Workspace mediante la delegación en todo el dominio. Sin pantalla de consentimiento ni navegador: solo un archivo de clave JSON.
from google.oauth2 import service_account
import os
SCOPES = [
'https://www.googleapis.com/auth/gmail.readonly',
'https://www.googleapis.com/auth/gmail.send'
]
def get_service_account_credentials(impersonate_user):
service_account_file = os.environ.get(
'GOOGLE_SERVICE_ACCOUNT_JSON',
'service-account.json'
)
credentials = service_account.Credentials.from_service_account_file(
service_account_file,
scopes=SCOPES
)
# Impersonate a real user (requires domain-wide delegation in Admin)
delegated = credentials.with_subject(impersonate_user)
return delegated
creds = get_service_account_credentials('agent@yourcompany.com')
print('Service account credentials ready')Creación del objeto de servicio de Gmail
Una vez que tenga las credenciales, use googleapiclient.discovery.build() para crear el objeto de servicio de Gmail. Esta es la interfaz principal para todas las llamadas a la Gmail API. Pase el nombre del servicio 'gmail' y la versión 'v1'.
from googleapiclient.discovery import build
def build_gmail_service(credentials):
service = build(
'gmail',
'v1',
credentials=credentials,
cache_discovery=False # avoid file warnings in some environments
)
return service
# Full setup: credentials -> service
creds = get_credentials() # or get_service_account_credentials()
gmail = build_gmail_service(creds)
# Test: get user profile
profile = gmail.users().getProfile(userId='me').execute()
print('Email:', profile['emailAddress'])
print('Total messages:', profile['messagesTotal'])Creación del objeto de servicio de Calendar
La misma configuración de credenciales funciona para Google Calendar. Solo tiene que crear el servicio con 'calendar' y 'v3'. Si necesita Gmail y Calendar en un mismo agente, cree ambos servicios a partir del mismo objeto de credenciales.
from googleapiclient.discovery import build
def build_google_services(credentials):
gmail = build(
'gmail', 'v1',
credentials=credentials,
cache_discovery=False
)
calendar = build(
'calendar', 'v3',
credentials=credentials,
cache_discovery=False
)
return gmail, calendar
# Use both in one agent
creds = get_credentials()
gmail_service, calendar_service = build_google_services(creds)
# Test calendar access
cal_list = calendar_service.calendarList().list().execute()
for cal in cal_list.get('items', []):
print(f'Calendar: {cal["summary"]}')Gestión de errores de las API de Google
Los errores de las API de Google se producen como googleapiclient.errors.HttpError. El error contiene un código de estado HTTP y un cuerpo JSON con los detalles del error. Capture siempre esta excepción y registre el estado y el mensaje para facilitar la depuración.
from googleapiclient.errors import HttpError
import json
def safe_gmail_call(service, user_id='me'):
try:
profile = service.users().getProfile(userId=user_id).execute()
return profile
except HttpError as e:
status = e.resp.status
try:
error_body = json.loads(e.content.decode())
message = error_body.get('error', {}).get('message', str(e))
except Exception:
message = str(e)
if status == 401:
print('AUTH ERROR: Credentials invalid or expired')
elif status == 403:
print(f'PERMISSION ERROR: {message}')
print('Check scopes and domain-wide delegation settings')
elif status == 429:
print('QUOTA EXCEEDED: Gmail API rate limit hit')
else:
print(f'Gmail API error {status}: {message}')
return NoneCuotas y límites de velocidad de la Gmail API
La Gmail API tiene cuotas de uso: 1.000 millones de unidades de cuota al día de forma predeterminada, y cada llamada cuesta entre 1 y 100 unidades según la operación. Leer mensajes cuesta más que enumerarlos. Use solicitudes por lotes y espera exponencial ante errores 429/503 para mantenerse dentro de los límites.
import time
from googleapiclient.errors import HttpError
def gmail_call_with_retry(func, max_retries=5):
for attempt in range(max_retries):
try:
return func()
except HttpError as e:
if e.resp.status in (429, 500, 503):
wait = (2 ** attempt) + 1
print(f'Quota/server error. Waiting {wait}s (attempt {attempt+1})')
time.sleep(wait)
elif e.resp.status == 403:
# Check if it's a quota exceeded vs permission error
import json
body = json.loads(e.content.decode())
reason = body.get('error', {}).get('errors', [{}])[0].get('reason', '')
if reason == 'rateLimitExceeded':
time.sleep(2 ** attempt)
else:
raise # real permission error, don't retry
else:
raise
raise Exception(f'Gmail API call failed after {max_retries} attempts')Almacenamiento seguro de las credenciales
Nunca incluya token.json, credentials.json ni service-account.json en el control de versiones. Añádalos a .gitignore. En producción, almacene el JSON de la cuenta de servicio en una variable de entorno o en un gestor de secretos y cárguelo durante la ejecución.
import json
import os
from google.oauth2 import service_account
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
def get_credentials_from_env():
# Load service account JSON from environment variable
sa_json = os.environ.get('GOOGLE_SERVICE_ACCOUNT_JSON')
if not sa_json:
raise EnvironmentError(
'GOOGLE_SERVICE_ACCOUNT_JSON env var not set. '
'Set it to the contents of your service-account.json'
)
sa_info = json.loads(sa_json)
credentials = service_account.Credentials.from_service_account_info(
sa_info,
scopes=SCOPES
)
return credentials
# In production: export GOOGLE_SERVICE_ACCOUNT_JSON=$(cat service-account.json)
creds = get_credentials_from_env()
print('Service account loaded from env var')Comprobación rápida: cuenta de servicio frente a OAuth de usuario
Compruebe su comprensión de los métodos de autenticación de la Gmail API.
Resumen de la conexión a la Gmail API
Ya puede conectar un agente a Gmail:
- OAuth de usuario: use
InstalledAppFlow+ almacenetoken.json; se actualiza automáticamente en las ejecuciones posteriores - Cuenta de servicio: cargue la clave JSON y llame a
.with_subject(user_email)para la delegación - Scopes: solicite los mínimos necesarios (
gmail.readonly,gmail.send,calendar.events) - Construya el servicio con
build('gmail', 'v1', credentials=creds) - Capture
HttpErrorpara los errores de la API; vuelva a intentarlo ante errores 429/503 - Nunca incluya archivos de credenciales en el control de versiones; use variables de entorno en producción
Preguntas frecuentes
¿La lección «Conexión con Gmail mediante la API» es gratis?
Sí — el texto completo de «Conexión con Gmail mediante la API» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de AI Agents, actualiza a CoddyKit PRO. El curso de AI Agents incluye 4 lecciones en total.
¿Qué aprenderé en «Conexión con Gmail mediante la API»?
Biblioteca cliente de Google API, consentimiento OAuth2 y selección de ámbitos de Gmail. Practicas AI Agents con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar AI Agents?
No se requiere experiencia previa. AI Agents en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.
¿Cuánto tiempo toma la lección «Conexión con Gmail mediante la API»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de AI Agents?
Sí. Cada lección de AI Agents incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Conexión con Gmail mediante la API
- Lectura y envío programático de correos electrónicos
- Creación y consulta de eventos de calendario
- Creación de un agente asistente de correo sencillo