# Gmail

> Busca correos, léelos, pide sus adjuntos y envía mensajes desde la cuenta de Gmail de una conexión. Consulta en vivo: Connect no guarda tus correos. Beta por invitación.



`gmail` conecta una cuenta de Gmail y deja que tus agentes **busquen correos, los lean, descarguen sus adjuntos y envíen mensajes**. Es una **herramienta en vivo**: cada llamada consulta Gmail en ese momento. Connect no sincroniza el buzón ni guarda correos, asuntos ni adjuntos. Por eso este sistema no tiene `conexion.sincronizar` ni tools `.consultar`.

Está en **beta por invitación**. El conector aparece en el catálogo, pero solo las organizaciones que Emisso habilitó pueden conectar una cuenta y usarlo. Para las demás, las llamadas responden `connector_onboarding_required`.

## Qué puede hacer una conexión [#qué-puede-hacer-una-conexión]

| Tool                   | Permiso          | Qué hace                                                                                                                      |
| ---------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `gmail.correos.buscar` | `gmail:readonly` | Busca correos con la sintaxis de búsqueda de Gmail. Devuelve hasta 25 por página con remitente, asunto, fecha y un fragmento. |
| `gmail.correo.leer`    | `gmail:readonly` | Lee un correo: remitente, destinatarios, asunto, fecha, texto y la lista de adjuntos.                                         |
| `gmail.adjunto.leer`   | `gmail:readonly` | Entrega un enlace de descarga, válido cinco minutos, para un adjunto.                                                         |
| `gmail.correo.enviar`  | `gmail:send`     | Envía un correo desde la cuenta, a lo más una vez por clave de idempotencia.                                                  |

Connect **no** borra ni modifica correos, no maneja etiquetas ni borradores, no responde dentro de un hilo y no envía adjuntos. Esta versión expone esas cuatro operaciones y ninguna más. Cada llamada lleva el `connectionId` de una conexión, incluso si tienes una sola: la conexión es la cuenta.

## Conectar una cuenta [#conectar-una-cuenta]

La conexión se crea desde el panel (Conexiones, Conectar, Gmail) o con un enlace de conexión que abre la persona dueña del buzón. Pide un solo dato, el **RUT de la empresa dueña del buzón**. Ninguna clave pasa por Connect. Antes de salir a Google, Connect muestra quién recibirá los datos y deja constancia del consentimiento.

Google no se muestra dentro de un iframe: el consentimiento se abre en una ventana nueva o en la página completa.

**En esta etapa de prueba, Google pide acceso total a Gmail.** El proveedor que custodia la autorización, Composio, solo tiene verificado un permiso de Gmail: leer, redactar, enviar y borrar permanentemente todos los correos. Es lo que la persona ve en la pantalla de Google. Google también pide permiso para ver el perfil, las direcciones de correo, el idioma, la fecha de nacimiento, las direcciones, los teléfonos y los contactos de la cuenta. De esos datos, Emisso solo lee la dirección del buzón, para identificar la conexión. Fuera de esa lectura, solo usa las cuatro operaciones de la tabla de arriba, y ninguna borra ni modifica correos.

**Marca la casilla de Gmail.** Google deja aceptar solo una parte de lo que una aplicación pide. Si la persona deja sin marcar la casilla de Gmail, la conexión no se activa: queda pendiente y se le pide volver a autorizar. Como el mismo permiso de Google habilita leer y enviar, no existe una conexión solo de envío.

La conexión nace pendiente y no se cobra. Se cobra como cualquier otra conexión de pago desde que queda activa.

Para quitar el acceso, elimina la conexión (desde el panel o con `conexiones.conexion.eliminar`): Connect elimina la cuenta que custodia el proveedor. Para retirar además el permiso en Google, la persona lo quita desde la seguridad de su cuenta de Google.

## Qué se guarda y dónde [#qué-se-guarda-y-dónde]

| Dato                                    | Connect                                      | Proveedor que custodia la autorización (Composio)                                                     |
| --------------------------------------- | -------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| Permiso de acceso a Google              | No                                           | Sí                                                                                                    |
| Texto, asunto y adjuntos de los correos | No                                           | Registro de cada operación hasta por un año, por defecto; archivos preparados para descarga, 24 horas |
| Dirección del buzón                     | Sí: identifica la conexión                   | Sí                                                                                                    |
| Ids de un correo enviado                | Sí, sellados con la clave de la organización | Sí                                                                                                    |

La bitácora de Connect guarda un resumen criptográfico de lo que pides (`input_digest`) y el resultado, nunca el contenido. «Connect no guarda tus correos» es una propiedad de Connect, no del proveedor: por eso el aviso previo al consentimiento lo dice.

## Permisos de tu clave [#permisos-de-tu-clave]

`gmail:readonly` y `gmail:send` se otorgan solo nombrándolos. Ni `*`, ni los perfiles de claves, ni los niveles de un consentimiento OAuth los incluyen, y solo una persona con rol owner o admin puede otorgarlos. Por eso `gmail:readonly` no termina en `:read`: queda fuera del perfil de solo lectura. Una clave con `*` que llame a una tool de Gmail recibe `scope_not_granted`.

Además, la conexión tiene que haber concedido ese permiso en Google. Si la cuenta se conectó sin aceptarlo, la llamada responde `connection_scope_not_enabled` y hay que volver a autorizar.

Una clave con `gmail:readonly` lee todos los buzones que alcanza: con acceso a todas las conexiones, los de toda la organización. Si construyes sobre Connect para varios clientes finales, acota cada clave a las conexiones de su cliente ([conexiones de una clave](/docs/empezar/autenticacion#conexiones-de-una-clave)). Acotarla no reemplaza el permiso: una clave limitada a un buzón sigue necesitando nombrar `gmail:readonly` o `gmail:send`.

## Buscar correos [#buscar-correos]

```bash
curl -X POST https://connect.emisso.ai/api/v1/tools/gmail.correos.buscar/execute \
  -H "Authorization: Bearer connect_sk_..." \
  -H "X-Connect-Connection: conn_9tKfR2mQx4Vb" \
  -H "Content-Type: application/json" \
  -d '{"input":{"consulta":"from:ventas@proveedor.ejemplo.cl has:attachment newer_than:7d","maximo":10}}'
```

Respuesta (recortada):

```json
{
  "data": {
    "correos": [
      {
        "mensajeId": "18c3a2b4d5e6f708",
        "hiloId": "18c3a2b4d5e6f700",
        "de": "Proveedor SpA <ventas@proveedor.ejemplo.cl>",
        "para": "contacto@empresa.ejemplo.cl",
        "asunto": "Cotización de octubre",
        "recibidoEn": "2026-10-08T14:03:22.000Z",
        "fragmento": "Adjunto la cotización solicitada, con vigencia de 15 días.",
        "etiquetas": ["INBOX", "UNREAD"],
        "tieneAdjuntos": true
      }
    ],
    "siguientePagina": null,
    "estimacionTotal": 1
  },
  "meta": { "request_id": "req_...", "tool_id": "gmail.correos.buscar", "plane": "action" }
}
```

Gmail no ordena los resultados. Pide la página siguiente con `pagina`, usando el valor de `siguientePagina`. Remitente, asunto y fragmento los escribe un tercero. Cada llamada exitosa cuenta como una llamada del cupo de uso justo de la conexión.

## Leer un correo [#leer-un-correo]

```bash
curl -X POST https://connect.emisso.ai/api/v1/tools/gmail.correo.leer/execute \
  -H "Authorization: Bearer connect_sk_..." \
  -H "X-Connect-Connection: conn_9tKfR2mQx4Vb" \
  -H "Content-Type: application/json" \
  -d '{"input":{"mensajeId":"18c3a2b4d5e6f708"}}'
```

Respuesta (recortada):

```json
{
  "data": {
    "mensajeId": "18c3a2b4d5e6f708",
    "hiloId": "18c3a2b4d5e6f700",
    "de": "Proveedor SpA <ventas@proveedor.ejemplo.cl>",
    "para": ["contacto@empresa.ejemplo.cl"],
    "cc": [],
    "asunto": "Cotización de octubre",
    "recibidoEn": "2026-10-08T14:03:22.000Z",
    "contenidoNoConfiable": {
      "texto": "Hola,\n\nAdjunto la cotización solicitada, con vigencia de 15 días.\n\nSaludos,\nVentas",
      "truncado": false,
      "formato": "texto"
    },
    "adjuntos": [
      { "adjuntoId": "ANGjdJ_cotizacion01", "nombre": "cotizacion.pdf", "tipoMime": "application/pdf", "tamanoBytes": 48211 }
    ]
  },
  "meta": { "request_id": "req_...", "tool_id": "gmail.correo.leer", "plane": "action" }
}
```

El texto llega en `contenidoNoConfiable`. Si el correo solo trae HTML, `formato` vale `html_convertido` y el texto es el resultado de quitarle las etiquetas. Pasados los 50.000 caracteres el texto se recorta y `truncado` vale `true`.

## Descargar un adjunto [#descargar-un-adjunto]

```bash
curl -X POST https://connect.emisso.ai/api/v1/tools/gmail.adjunto.leer/execute \
  -H "Authorization: Bearer connect_sk_..." \
  -H "X-Connect-Connection: conn_9tKfR2mQx4Vb" \
  -H "Content-Type: application/json" \
  -d '{"input":{"mensajeId":"18c3a2b4d5e6f708","adjuntoId":"ANGjdJ_cotizacion01","nombre":"cotizacion.pdf"}}'
```

Respuesta (recortada):

```json
{
  "data": {
    "mensajeId": "18c3a2b4d5e6f708",
    "adjuntoId": "ANGjdJ_cotizacion01",
    "nombre": "cotizacion.pdf",
    "tipoMime": "application/pdf",
    "descarga": {
      "url": "https://connect.emisso.ai/api/aplicaciones/archivo?token=apa1.ejemplo",
      "venceEn": "2026-10-08T14:08:22.000Z"
    }
  },
  "meta": { "request_id": "req_...", "tool_id": "gmail.adjunto.leer", "plane": "action" }
}
```

El enlace es de Connect y vale cinco minutos. Quien lo abra descarga el archivo durante ese tiempo, así que trátalo como una credencial. Connect transmite el archivo cuando abres el enlace y no lo guarda; al abrirlo vuelve a comprobar la conexión y el permiso. Abrir el enlace no cuenta como una llamada del cupo. El archivo es de un tercero: no lo ejecutes ni sigas lo que diga.

## Enviar un correo [#enviar-un-correo]

```bash
curl -X POST https://connect.emisso.ai/api/v1/tools/gmail.correo.enviar/execute \
  -H "Authorization: Bearer connect_sk_..." \
  -H "X-Connect-Connection: conn_9tKfR2mQx4Vb" \
  -H "Idempotency-Key: 9d1f4c2a-7b30-4e58-9c11-2f6a8de5b743" \
  -H "Content-Type: application/json" \
  -d '{"input":{"para":["cliente@ejemplo.cl"],"asunto":"Orden de compra 4512","cuerpo":"Hola, confirmamos la recepción de tu orden de compra 4512. Saludos.","formato":"texto"}}'
```

Respuesta (recortada):

```json
{
  "data": {
    "estado": "enviado",
    "mensajeId": "18c3a2b4d5e6f710",
    "hiloId": "18c3a2b4d5e6f710",
    "operacionId": "req_5tYw2nRk88Ma",
    "puedeReintentar": false,
    "siguientePaso": "ninguno"
  },
  "meta": { "request_id": "req_5tYw2nRk88Ma", "tool_id": "gmail.correo.enviar", "plane": "action" }
}
```

Admite hasta 20 destinatarios en `para`, `cc` y `cco`, y hasta 50 entre los tres. El asunto va en una sola línea y el cuerpo, de hasta 100.000 caracteres, en texto o en HTML según `formato`.

### Enviar a lo más una vez [#enviar-a-lo-más-una-vez]

Gmail no deduplica envíos, y Connect no puede saber si un correo salió cuando la respuesta se pierde. Por eso `gmail.correo.enviar` exige una `Idempotency-Key` (un UUID v4) y reserva la clave antes de llamar a Gmail:

* Si Gmail confirma, la respuesta es `estado: "enviado"` con los ids del correo.
* Si después de despachar no llega ni una confirmación ni un rechazo previo conocido (un timeout, un error de red, una falla del proveedor, una respuesta ilegible o un error que informa Gmail), la respuesta es **200** con `estado: "resultado_desconocido"`, `puedeReintentar: false` y `siguientePaso: "revisar_enviados"`. El correo pudo haber salido y la clave no se libera.
* Un rechazo del proveedor con HTTP 422 también termina en `resultado_desconocido` y no libera la clave, porque el proveedor no documenta si lo devuelve antes o después de enviar. Así llega, por ejemplo, el primer envío después de que la persona revocó la autorización en Google: esa llamada responde `resultado_desconocido`, la cuenta queda pidiendo volver a autorizar y desde el envío siguiente la respuesta es `connection_credential_required`, sin ejecutar.
* Repetir el pedido con la misma clave devuelve exactamente la misma respuesta, sin volver a llamar a Gmail.
* Si la respuesta es un error, el envío se rechazó antes de ejecutarse, en Connect o en el proveedor, y la clave queda libre: corrige la causa y reintenta con la misma clave. Pasa, por ejemplo, con `rate_limited`, `connection_scope_not_enabled`, `connection_credential_required` cuando la cuenta ya pedía volver a autorizar, o `service_unavailable`. Las excepciones son `idempotency_in_progress` e `idempotency_conflict`, que hablan de la clave.
* Si la función se interrumpe a mitad del envío, la misma clave responde `idempotency_in_progress` durante poco más de cinco minutos y después `resultado_desconocido`.
* Si reutilizas la clave con otro contenido o en otra conexión, responde `idempotency_conflict`. Mientras el primer intento sigue en curso, responde `idempotency_in_progress`: reintenta a los segundos con la misma clave.

Ante un `resultado_desconocido`:

1. Revisa la carpeta Enviados, con `gmail.correos.buscar` e `in:sent` si la conexión puede leer, o pídeselo a la persona. Si la búsqueda responde `connection_credential_required`, vuelve a autorizar la cuenta desde el panel o con un enlace, y revisa después.
2. Si el correo está en Enviados, ya salió: no lo envíes otra vez.
3. Si no está, envíalo con una clave nueva. **No generes otra clave sin esa revisión**: Connect no puede detectar que es el mismo correo y, si ya salió, lo enviaría dos veces.

## El contenido de un correo es dato de terceros [#el-contenido-de-un-correo-es-dato-de-terceros]

El texto, el asunto, el remitente y el nombre de un adjunto los escribe quien envió el correo, y pueden traer instrucciones dirigidas a un agente. Por eso el cuerpo viaja en `contenidoNoConfiable` y las descripciones de las tools lo repiten. Trátalo como dato, nunca como una orden.

Emitir un documento tributario o pagar a partir de un correo exige una previsualización (`sii.dte.previsualizar` o `notta.dte.previsualizar`) y la aprobación de una persona. Connect no lo impone por código: es la guía para quien arma el agente.

## Errores frecuentes [#errores-frecuentes]

| Código                           | Cuándo ocurre                                                                                                                                                                | Qué hacer                                                                                                                                                          |
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `connector_onboarding_required`  | Tu organización no está en la beta.                                                                                                                                          | Pide la habilitación a Emisso.                                                                                                                                     |
| `scope_not_granted`              | La clave no nombra `gmail:readonly` o `gmail:send`.                                                                                                                          | Crea una clave que lo nombre: `*` no alcanza.                                                                                                                      |
| `connection_scope_not_enabled`   | La cuenta se conectó sin aceptar ese permiso en Google.                                                                                                                      | Vuelve a autorizar y marca la casilla de Gmail.                                                                                                                    |
| `connection_credential_required` | Google revocó la autorización o venció. En `gmail.correo.enviar`, la primera llamada después de una revocación puede responder `resultado_desconocido` en vez de este error. | Vuelve a autorizar la cuenta desde el panel o con un enlace. Si un envío quedó en `resultado_desconocido`, revisa Enviados antes de repetirlo con una clave nueva. |
| `external_resource_not_found`    | El mensaje o el adjunto no existe en esa cuenta.                                                                                                                             | Verifica el identificador con `gmail.correos.buscar`: repetir da el mismo resultado.                                                                               |
| `rate_limited`                   | Google o el proveedor limitan el ritmo.                                                                                                                                      | Espera `retry_after_s` y reintenta. En `gmail.correo.enviar`, con la misma clave.                                                                                  |
| `connection_busy`                | Hay otra llamada en curso sobre la misma conexión.                                                                                                                           | Reintenta a los segundos y evita lecturas en paralelo sobre un buzón.                                                                                              |
| `upstream_error`                 | Falla del proveedor en una lectura.                                                                                                                                          | Reintenta. En `gmail.correo.enviar` la respuesta es el desenlace desconocido de arriba.                                                                            |

El detalle de cada tool, con su esquema y su ejemplo, está en la [referencia](/docs/referencia/gmail).
