# Enviar un email

> Envía email con POST /emails. Reglas del remitente, destinatarios, contenido, plantillas, seguimiento, la respuesta, los eventos de webhook y todos los códigos de error.

Esta guía explica cada parte de una petición `POST /emails` y lo que Emailit hace con ella, desde la dirección From hasta los errores que puedes recibir. Para la referencia completa de parámetros, consulta [Enviar un email](/es/docs/api-reference/emails/send/) en la referencia de la API.

## Antes de empezar

- Un dominio de envío verificado en tu espacio de trabajo. Consulta [Añadir un dominio](/es/docs/domains/add-a-domain/).
- Una clave de API con el permiso **Full Access** o **Sending Only**. Consulta [Claves de API](/es/docs/developers/api-keys/).
- Acceso de producción si envías a alguien que no sea miembro de tu espacio de trabajo. Consulta [Acceso de producción](/es/docs/workspaces/production-access/).
- Créditos suficientes para todos los destinatarios (1 crédito cada uno).

## Enviar un email básico

**cURL**

```bash
curl https://api.emailit.com/v2/emails \
  -H "Authorization: Bearer $EMAILIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme Billing <billing@acme.com>",
    "to": ["ada@example.com", "Grace Hopper <grace@example.com>"],
    "cc": "accounts@example.com",
    "reply_to": "support@acme.com",
    "subject": "Your invoice for October",
    "html": "<p>Your invoice is ready.</p>",
    "text": "Your invoice is ready."
  }'
```

**Node.js**

```javascript
import { Emailit } from '@emailit/node';

const emailit = new Emailit(process.env.EMAILIT_API_KEY);

const email = await emailit.emails.send({
  from: 'Acme Billing <billing@acme.com>',
  to: ['ada@example.com', 'Grace Hopper <grace@example.com>'],
  cc: 'accounts@example.com',
  reply_to: 'support@acme.com',
  subject: 'Your invoice for October',
  html: '<p>Your invoice is ready.</p>',
  text: 'Your invoice is ready.',
});
```

**Python**

```python
import os
from emailit import EmailitClient

client = EmailitClient(os.environ["EMAILIT_API_KEY"])

email = client.emails.send({
    "from": "Acme Billing <billing@acme.com>",
    "to": ["ada@example.com", "Grace Hopper <grace@example.com>"],
    "cc": "accounts@example.com",
    "reply_to": "support@acme.com",
    "subject": "Your invoice for October",
    "html": "<p>Your invoice is ready.</p>",
    "text": "Your invoice is ready.",
})
```

**PHP**

```php
$emailit = Emailit::client(getenv('EMAILIT_API_KEY'));

$email = $emailit->emails()->send([
    'from' => 'Acme Billing <billing@acme.com>',
    'to' => ['ada@example.com', 'Grace Hopper <grace@example.com>'],
    'cc' => 'accounts@example.com',
    'reply_to' => 'support@acme.com',
    'subject' => 'Your invoice for October',
    'html' => '<p>Your invoice is ready.</p>',
    'text' => 'Your invoice is ready.',
]);
```

## Definir la dirección From

`from` es obligatorio y admite una dirección en cualquiera de estas formas:

- `billing@acme.com`
- `Acme Billing <billing@acme.com>`, o con comillas, `"Acme, Inc." <billing@acme.com>`

El dominio que sigue a la `@` debe ser un dominio de envío verificado en el mismo espacio de trabajo:

- **La coincidencia es exacta.** Los dominios se comparan sin distinguir mayúsculas y minúsculas, pero `mail.acme.com` y `acme.com` son dominios distintos. Añade y verifica cada subdominio desde el que envíes.
- **Cualquier parte local sirve.** No necesitas un buzón para `billing@` o `no-reply@`.
- **Los dominios pendientes no pueden enviar.** Un dominio que todavía espera la revisión (**Pending verification**) se trata como no verificado.
- **Las claves limitadas se quedan en su dominio.** Una clave **Sending Only** limitada a un dominio solo puede enviar desde ese dominio.
- **Los dominios pausados están bloqueados.** Si la [salud de envío](/es/docs/deliverability/sending-health/) ha pausado el dominio, los envíos desde él se rechazan hasta que se levante la pausa.

## Añadir destinatarios

`to` es obligatorio. `cc` y `bcc` son opcionales. Cada campo acepta una cadena o un array de cadenas, con o sin nombre visible, y admite hasta 50 direcciones. Una cadena puede contener varias direcciones separadas por comas; usa un array cuando el propio nombre visible contenga una coma.

Emailit elimina los duplicados entre `to`, `cc` y `bcc` (sin distinguir mayúsculas y minúsculas) y después crea **un email por destinatario único**, cada uno con su propio ID `em_`. Todas las copias llevan las mismas cabeceras `To` y `Cc`, así que los destinatarios ven la conversación como siempre, y los destinatarios de `Bcc` no aparecen nunca en las cabeceras de ninguna copia.

Cuando una petición tiene más de un destinatario, la respuesta incluye un mapa `ids` que asocia cada destinatario con el ID de su email. `id` es el email del primer destinatario.

```json
{
  "object": "email",
  "id": "em_33VtK8mRq1xZp7LwN4cY2bHsDfa",
  "ids": {
    "ada@example.com": "em_33VtK8mRq1xZp7LwN4cY2bHsDfa",
    "grace@example.com": "em_33VtK8nB5rTq0YxW3mJk9PdLsUe",
    "accounts@example.com": "em_33VtK8nQ2wErT6yU8iOp4AsDf7g"
  }
}
```

Cada destinatario cuesta 1 crédito y cuenta para tus [límites de velocidad](/es/docs/api-reference/rate-limits/). Un destinatario con un [bloqueo](/es/docs/suppressions/) de tipo `recipient` se acepta y después se marca como `suppressed` en lugar de entregarse.

## Escribir el contenido

| Campo | Reglas |
| --- | --- |
| `subject` | Obligatorio, salvo que lo aporte una plantilla. Emailit codifica por ti los caracteres no ASCII. |
| `html` | El cuerpo HTML. Necesitas `html`, `text` o ambos, salvo que los aporte una plantilla. |
| `text` | El cuerpo en texto plano. Envíalo junto con `html`: algunos clientes y filtros de spam prefieren los mensajes que tienen ambos. |
| `reply_to` | Una cadena o un array de direcciones a las que deben ir las respuestas. |

Si `reply_to` indica la misma dirección que `from`, Emailit quita la cabecera `Reply-To`, porque no aporta nada y algunos filtros de spam la penalizan.

## Enviar con una plantilla

Pon en `template` un alias de plantilla o un ID `tem_`, y pasa `variables` para los marcadores de [Temple](/es/docs/templates/temple/) que contenga.

- **Un alias** envía la versión publicada en ese momento para ese alias. Si no hay ninguna versión publicada, la petición falla con `404`.
- **Un ID `tem_`** envía exactamente esa versión, esté publicada o no. Úsalo para probar una versión en borrador antes de publicarla.

Los campos de la petición tienen prioridad sobre la plantilla: un `subject`, `html` o `text` que envíes sustituye al valor de la plantilla. Si no envías `reply_to`, se usa el Reply-To de la plantilla. `from` siempre es obligatorio en la petición. Para saber cómo funciona la publicación, consulta [Versiones de plantilla](/es/docs/templates/versions/).

**cURL**

```bash
curl https://api.emailit.com/v2/emails \
  -H "Authorization: Bearer $EMAILIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme <hello@acme.com>",
    "to": "ada@example.com",
    "template": "welcome-email",
    "variables": {
      "first_name": "Ada",
      "plan": "Pro",
      "activation_url": "https://acme.com/activate?token=8f3k2"
    }
  }'
```

**Node.js**

```javascript
const email = await emailit.emails.send({
  from: 'Acme <hello@acme.com>',
  to: 'ada@example.com',
  template: 'welcome-email',
  variables: {
    first_name: 'Ada',
    plan: 'Pro',
    activation_url: 'https://acme.com/activate?token=8f3k2',
  },
});
```

**Python**

```python
email = client.emails.send({
    "from": "Acme <hello@acme.com>",
    "to": "ada@example.com",
    "template": "welcome-email",
    "variables": {
        "first_name": "Ada",
        "plan": "Pro",
        "activation_url": "https://acme.com/activate?token=8f3k2",
    },
})
```

**PHP**

```php
$email = $emailit->emails()->send([
    'from' => 'Acme <hello@acme.com>',
    'to' => 'ada@example.com',
    'template' => 'welcome-email',
    'variables' => [
        'first_name' => 'Ada',
        'plan' => 'Pro',
        'activation_url' => 'https://acme.com/activate?token=8f3k2',
    ],
]);
```

`variables` también funciona sin plantilla: Emailit renderiza los marcadores de Temple del `subject`, el `html` y el `text` que envías directamente en la petición.

## Controlar el seguimiento

Por defecto, cada email sigue la configuración **Track loads** y **Track clicks** de su dominio de envío. Puedes cambiarla para cada email con `tracking`:

- `"tracking": true` o `false` activa o desactiva a la vez el seguimiento de cargas (aperturas) y de clics.
- `"tracking": { "loads": true, "clicks": false }` define cada uno por separado.

El seguimiento solo funciona cuando el CNAME de seguimiento del dominio está verificado. Sin él, el email se envía sin seguimiento y la petición se completa igualmente. El objeto `tracking` de la respuesta muestra la configuración que se ha aplicado realmente. Consulta [Seguimiento de aperturas y clics](/es/docs/tracking/).

## Añadir cabeceras y metadatos

Usa `headers` para las cabeceras de email personalizadas, como `List-Unsubscribe`, y `meta` para tus propios pares clave-valor de tipo cadena. Emailit guarda `meta` con el email y lo incluye en los eventos de webhook. Consulta [Cabeceras y metadatos](/es/docs/email-api/headers-and-metadata/).

Para adjuntar archivos, programar el envío o hacer que los reintentos sean seguros, consulta [Adjuntos](/es/docs/email-api/attachments/), [Programación](/es/docs/email-api/scheduling/) e [Idempotencia](/es/docs/email-api/idempotency/).

## Leer la respuesta

Una petición correcta devuelve `200`:

| Campo | Descripción |
| --- | --- |
| `object` | Siempre `email`. |
| `id` | El ID `em_` del email del primer destinatario. |
| `ids` | Mapa de dirección del destinatario a ID del email. Solo aparece con más de un destinatario. |
| `token` | El token interno del primer email, que también se usa en su Message-ID. |
| `message_id` | La cabecera `Message-ID` del primer email, con el formato `<token@your-domain>`. |
| `from` | La dirección From tal como la enviaste. |
| `to` | Las direcciones de `to`, sin nombres visibles. |
| `cc`, `bcc` | Las direcciones de `cc` y `bcc`. Solo aparecen si las enviaste. |
| `subject` | El asunto final, después de renderizar la plantilla. |
| `status` | `accepted`, o `scheduled` cuando el email tiene una hora de envío futura. |
| `scheduled_at` | La hora de envío en formato ISO 8601, o `null`. |
| `created_at` | Cuándo se creó el email. |
| `tracking` | La configuración de `loads` y `clicks` aplicada. |

Guarda el `id` (o el mapa `ids`) para poder asociar después los eventos de webhook y buscar el email con [Obtener un email](/es/docs/api-reference/emails/get/).

## Eventos

El email de cada destinatario emite sus propios eventos:

1. [`email.accepted`](/es/docs/webhooks/events/email/accepted/) justo después de la petición, o [`email.scheduled`](/es/docs/webhooks/events/email/scheduled/) si tiene una hora de envío futura.
2. Eventos de entrega a medida que el email avanza por el proceso de entrega: [`email.delivered`](/es/docs/webhooks/events/email/delivered/), [`email.attempted`](/es/docs/webhooks/events/email/attempted/) (fallo temporal, se reintentará), [`email.bounced`](/es/docs/webhooks/events/email/bounced/), [`email.failed`](/es/docs/webhooks/events/email/failed/), [`email.rejected`](/es/docs/webhooks/events/email/rejected/) o [`email.suppressed`](/es/docs/webhooks/events/email/suppressed/). Un email retenido para revisión emite `email.held`.
3. Eventos de interacción, si el seguimiento está activado: [`email.loaded`](/es/docs/webhooks/events/email/loaded/) y [`email.clicked`](/es/docs/webhooks/events/email/clicked/). Las quejas por spam emiten [`email.complained`](/es/docs/webhooks/events/email/complained/).

Para saber qué significa cada estado, consulta [Estados de los emails](/es/docs/logs/email-statuses/).

## Errores

Los errores de validación devuelven una lista con todos los problemas encontrados:

```json
{
  "error": "Validation failed",
  "validation_errors": [
    "Missing required field: subject",
    "Invalid to email address at index 1: grace@"
  ]
}
```

| Estado | `error` | Causa | Solución |
| --- | --- | --- | --- |
| `400` | `Validation failed` | Falta un campo obligatorio, una dirección tiene un formato incorrecto, un campo tiene más de 50 destinatarios o un adjunto no es válido. | Corrige cada elemento de `validation_errors`. |
| `400` | `Invalid Idempotency-Key` | La cabecera `Idempotency-Key` tiene un formato incorrecto. | Usa 1–256 letras, dígitos, `-` o `_`. Consulta [Idempotencia](/es/docs/email-api/idempotency/). |
| `401` | `Unauthorized` | Falta la clave de API o no es válida. | Envía `Authorization: Bearer` con una clave vigente. |
| `402` | `Insufficient credits` | El espacio de trabajo no puede pagar todos los destinatarios. | [Compra créditos](/es/docs/billing/credits/) o activa la [recarga automática](/es/docs/billing/auto-refill/). |
| `403` | `Workspace not verified` | El espacio de trabajo está en modo sandbox y un destinatario no es miembro del espacio de trabajo. `code` es `unverified_workspace_recipient` y `blocked_recipients` lista las direcciones. | [Solicita el acceso de producción](/es/docs/workspaces/production-access/), o haz pruebas con las direcciones de los miembros. |
| `403` | `Domain not authorized` | La clave de API está limitada a otro dominio de envío. | Envía desde el dominio de la clave, o usa una clave sin limitación de dominio. |
| `403` | `Domain paused` | La salud de envío ha pausado el dominio From. | Consulta [Salud de envío](/es/docs/deliverability/sending-health/). |
| `404` | `Template not found` | El alias no tiene ninguna versión publicada, o el ID `tem_` no existe en este espacio de trabajo. | Publica una versión o comprueba el ID. |
| `409` | `Idempotency key in progress` | Todavía se está procesando otra petición con la misma clave. | Espera y reinténtalo con la misma clave. |
| `413` | `Message too large` | El mensaje codificado ocupa más de 40 MB. | Envía menos adjuntos o adjuntos más pequeños, o enlaza a los archivos grandes. |
| `422` | `Domain not verified` | El dominio From no es un dominio de envío verificado en este espacio de trabajo. | Verifica el dominio, o comprueba si se trata de un subdominio o de una errata. |
| `422` | `Attachment error` | No se ha podido descargar la URL de un adjunto o el archivo ocupa más de 25 MB. | Consulta [Adjuntos](/es/docs/email-api/attachments/). |
| `429` | `Rate limit exceeded` o `Daily limit exceeded` | Has superado el límite de envío por segundo o el diario. | Espera los segundos que indique `retry-after`, o solicita un límite más alto. |
| `503` | `Idempotency unavailable` | No se ha podido acceder al almacén de idempotencia. | Reinténtalo con la misma clave. |

Un espacio de trabajo suspendido recibe `403` con `Workspace is suspended` en cada envío. Para el formato general de los errores, consulta [Errores](/es/docs/api-reference/errors/).

## Ver también

- Referencia de la API: [Enviar un email](/es/docs/api-reference/emails/send/)
- [Plantillas](/es/docs/templates/)
- [Estados de los emails](/es/docs/logs/email-statuses/)
- [Tipos de eventos de webhook](/es/docs/webhooks/event-types/)
- [¿Por qué no ha llegado mi email?](/es/docs/kb/email-not-delivered-checklist/)

---
Fuente: https://emailit.com/es/docs/email-api/send-email/
