Guía práctica
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 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.
- Una clave de API con el permiso Full Access o Sending Only. Consulta Claves de API.
- Acceso de producción si envías a alguien que no sea miembro de tu espacio de trabajo. Consulta Acceso de producción.
- Créditos suficientes para todos los destinatarios (1 crédito cada uno).
Enviar un email básico
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."
}'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.',
});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.",
})$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.comAcme 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.comyacme.comson dominios distintos. Añade y verifica cada subdominio desde el que envíes. - Cualquier parte local sirve. No necesitas un buzón para
billing@ono-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 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.
{
"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. Un destinatario con un bloqueo 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 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.
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"
}
}'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',
},
});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",
},
})$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": trueofalseactiva 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.
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.
Para adjuntar archivos, programar el envío o hacer que los reintentos sean seguros, consulta Adjuntos, Programación e Idempotencia.
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.
Eventos
El email de cada destinatario emite sus propios eventos:
email.acceptedjusto después de la petición, oemail.scheduledsi tiene una hora de envío futura.- Eventos de entrega a medida que el email avanza por el proceso de entrega:
email.delivered,email.attempted(fallo temporal, se reintentará),email.bounced,email.failed,email.rejectedoemail.suppressed. Un email retenido para revisión emiteemail.held. - Eventos de interacción, si el seguimiento está activado:
email.loadedyemail.clicked. Las quejas por spam emitenemail.complained.
Para saber qué significa cada estado, consulta Estados de los emails.
Errores
Los errores de validación devuelven una lista con todos los problemas encontrados:
{
"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. |
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 o activa la recarga automática. |
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, 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. |
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. |
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.