Nuevos usuariosPlanes gratuitos de DNS y CDN para cada cuenta nueva.Crear una cuenta

SMTP y API HTTP

Cree claves de API y envíe correo por SMTP o mediante la API HTTP, con campos de solicitud, respuestas, códigos de error y ejemplos.

10 min de lectura Actualizado 20 oct 2026

Puede enviar a través de un flujo de dos maneras: por SMTP desde cualquier aplicación o biblioteca de correo, o con la API HTTP. Ambas usan las mismas claves de API, cuotas, lista de supresión y eventos. Antes de empezar, verifique un dominio de envío y cree una clave de API.

Claves de API

  1. Abra el flujo y vaya a la pestaña Clave de API.
  2. Haga clic en Crear clave, introduzca un Nombre como production y confirme.
  3. Copie la clave que se muestra y haga clic en Ya lo guardé. La clave solo se muestra esta vez. Después, la lista solo muestra su Prefijo, como ytm_aB3dE6gH….

Cada clave empieza por ytm_. Un flujo puede tener hasta 20 claves activas. La lista muestra cuándo se usó cada clave por última vez. Para retirar una clave, haga clic en Revocar: los programas que la usan dejan de funcionar de inmediato. Una clave solo funciona para el flujo al que pertenece.

Advertencia

Guarde las claves de API en su servidor. No las incluya en código de navegador, aplicaciones móviles ni repositorios públicos. Cualquiera que tenga la clave puede enviar correo en nombre de su dominio.

SMTP

La pestaña Resumen del flujo muestra la configuración SMTP:

ConfiguraciónValor
HostEl host SMTP que se muestra para el flujo, normalmente smtp.tm.yeapcloud.net
Puerto587 con STARTTLS, o 465 con TLS
Nombre de usuarioapikey (literalmente esta palabra)
ContraseñaUna clave de API de este flujo
Encabezado de categoríaX-Yeap-Category

Use el host que se muestra en la consola. Algunos flujos envían a través de otro grupo de servidores con su propio nombre de host.

Cómo funciona el envío por SMTP:

  • El encabezado From debe usar una dirección de un dominio verificado para el flujo.
  • Cada destinatario (To, Cc y Bcc) recibe su propia copia con su propio ID de mensaje, y cuenta como un correo.
  • Para establecer una categoría, añada un encabezado como X-Yeap-Category: password-reset. Se elimina antes de la entrega. Los caracteres permitidos son letras, dígitos, ., _ y -, con un máximo de 64 caracteres.
  • Un mensaje puede ocupar hasta 25 MB, con un máximo de 1,000 destinatarios por transacción SMTP.
  • Cada mensaje recibe un encabezado X-TM-ID (el ID de mensaje que aparece en el registro de envíos y en los eventos) y un encabezado Feedback-ID para los bucles de retroalimentación de los proveedores de correo.
  • En los flujos de marketing, cualquier encabezado List-Unsubscribe que usted establezca se sustituye por los encabezados de baja con un clic de Yeap Cloud. SMTP no modifica el cuerpo del mensaje, así que añada usted mismo su dirección postal y un enlace de baja al contenido. Consulte Supresiones y bajas.
  • El seguimiento de aperturas y clics solo está disponible a través de la API HTTP.

Ejemplo con la biblioteca estándar de Python:

python
import smtplib
from email.message import EmailMessage

msg = EmailMessage()
msg["From"] = "Example <noreply@example.com>"
msg["To"] = "user@example.org"
msg["Subject"] = "Reset your password"
msg["X-Yeap-Category"] = "password-reset"
msg.set_content("Click the link to reset your password: https://example.com/reset/abc")

with smtplib.SMTP("smtp.tm.yeapcloud.net", 587) as s:
    s.starttls()
    s.login("apikey", "ytm_your_api_key")
    s.send_message(msg)

Códigos de respuesta SMTP

Cuando el servidor rechaza un mensaje, el código de respuesta indica el motivo. Los códigos 4xx son temporales: vuelva a intentarlo más tarde. Los códigos 5xx son permanentes: corrija la causa antes de volver a enviar.

CódigoMensajeCausa y qué hacer
535 5.7.8Authentication failed / API key revokedNombre de usuario o clave incorrectos, o la clave fue revocada. El nombre de usuario debe ser apikey.
454 4.7.0Temporary authentication failure / Too many authentication failuresEl servidor aún no está listo, o su IP ha fallado demasiadas veces al iniciar sesión. Espere y vuelva a intentarlo.
451 4.7.1Stream is pausedEl flujo se pausó automáticamente. Consulte el motivo en el flujo y póngase en contacto con soporte.
550 5.7.1Stream is banned / suspended / terminatedEl flujo fue bloqueado, su suscripción está suspendida o fue liberado.
550 5.7.1From domain … is not verified for this streamVerifique el dominio o compruebe que está compartido con este flujo o vinculado a él.
550 5.7.1Sandbox mode: recipient is not a verified addressEl flujo está en el sandbox. Verifique el destinatario o envíe a su propio dominio.
550 5.7.1Recipient is on a suppression list / All recipients are suppressedLa dirección está suprimida (rebote, queja, baja o manual).
452 4.7.1Hourly sending limit reached, try laterSe ha agotado el límite por hora (o el límite diario del sandbox). Vuelva a intentarlo en la hora siguiente.
550 5.7.1Monthly sending quota exhaustedSe ha agotado el volumen mensual y no se permite excedente: en el plan gratuito, o cuando se alcanza el límite de gasto de excedente.
452 4.5.3Too many recipientsMás de 1,000 destinatarios en una transacción.
553 5.1.3Invalid recipient addressLa dirección del destinatario tiene un formato incorrecto.
554 5.7.1Message rejected: virus detectedEl mensaje contenía un virus. El flujo se bloquea de inmediato y se revocan todas sus claves de API.
554 5.7.1Message rejected as spamEl contenido se calificó como spam. Los rechazos repetidos pausan el flujo.
451 4.3.0Content scanner unavailable, try again laterEl correo de marketing solo se acepta después del análisis. Vuelva a intentarlo más tarde. Las demás respuestas 451 4.3.0 son errores temporales del servidor: vuelva a intentarlo.
554 5.6.0Malformed message headersCorrija los encabezados del mensaje.

API HTTP

ElementoValor
URL basehttps://api.tm.yeapcloud.net/v1 (también disponible como https://api.yeap.cloud/api/tm/v1)
AutenticaciónAuthorization: Bearer ytm_your_api_key
FormatoCuerpos de solicitud y respuesta en JSON, Content-Type: application/json
Límite de frecuencia600 solicitudes por minuto por clave de API

Los errores devuelven un código de estado HTTP y un cuerpo como este:

json
{"error": {"code": "invalid_request", "message": "subject is required (single line)"}}
Estado HTTPerror.codeSignificado
400invalid_json, invalid_requestEl cuerpo no es un objeto JSON, o un lote está vacío o es demasiado grande
401unauthorizedClave de API ausente, con formato incorrecto, revocada o desconocida
403stream_paused, stream_banned, stream_suspendedEl flujo no puede enviar
403from_domain_unverified, invalid_fromEl dominio From no está verificado para este flujo, o la dirección From no es válida
403postal_address_requiredFlujo de marketing sin dirección postal. Rellénela en la pestaña Ajustes de marketing.
403virusUn adjunto contenía un virus. El flujo queda bloqueado.
404not_foundEl mensaje no existe en este flujo
422invalid_requestFalta un campo o no es válido. message indica cuál.
429rate_limitedMás de 600 solicitudes en un minuto. Reduzca el ritmo y vuelva a intentarlo.
503no_nodeNo hay ningún servidor de envío disponible en este momento. Vuelva a intentarlo más tarde.

Enviar un mensaje: POST /v1/send

CampoTipoDescripción
fromstringObligatorio. Una dirección, como noreply@example.com o Example <noreply@example.com>. El dominio debe estar verificado para el flujo.
tostring o arrayObligatorio. Una dirección, una cadena separada por comas o un array. Los elementos del array también pueden ser objetos {"email": "...", "name": "..."}.
cc, bccstring o arrayOpcional. Mismo formato que to. Las direcciones Bcc no aparecen en los encabezados.
reply_tostring o arrayOpcional. Dirección Reply-To.
subjectstringObligatorio. Una línea, de hasta 998 caracteres.
html, textstringSe requiere al menos uno. Envíe ambos para obtener los mejores resultados.
headersobjectEncabezados adicionales opcionales, como {"X-Campaign": "spring"}. Los encabezados estándar (From, To, Subject, Reply-To, Message-ID, List-Unsubscribe, etc.) no se pueden establecer aquí.
attachmentsarrayOpcional. Elementos {"filename": "invoice.pdf", "content_base64": "...", "type": "application/pdf"}. Como máximo 10 archivos y 10 MB en total.
categorystringOpcional. Letras, dígitos, ., _, -, con un máximo de 64 caracteres.
tagsarray de stringsOpcional. Hasta 10 etiquetas para su propio filtrado, cada una de hasta 64 caracteres.
track_opens, track_clicksbooleanOpcional. Activa o desactiva para este mensaje el seguimiento de aperturas (un píxel de seguimiento) y el seguimiento de clics (enlaces reescritos a través de t.tm.yeapcloud.net). Solo HTML. Si se omiten, se aplica el valor predeterminado del flujo. Ambos están desactivados de forma predeterminada.
variablesobjectOpcional. Sustituye los marcadores {{name}} en subject, html y text. Los valores se escapan como HTML en html. Los marcadores desconocidos se dejan tal cual.

Una sola llamada puede tener hasta 50 destinatarios en total entre to, cc y bcc. Cada destinatario recibe una copia independiente con su propio ID de mensaje. Para enviar contenido diferente a muchas personas, use el endpoint de lotes.

Ejemplo:

bash
curl -X POST https://api.tm.yeapcloud.net/v1/send \
  -H "Authorization: Bearer ytm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Example <noreply@example.com>",
    "to": ["alice@example.org"],
    "subject": "Your order {{order_id}} has shipped",
    "html": "<p>Hi {{name}}, your order is on its way.</p>",
    "text": "Hi {{name}}, your order is on its way.",
    "category": "shipping",
    "tags": ["order"],
    "variables": {"name": "Alice", "order_id": "A-1024"}
  }'

Respuesta:

json
{
  "message_ids": ["01JAQ3Z9V8K4M2N6P7R5S1T0XW"],
  "rejected": []
}

message_ids enumera las copias aceptadas. rejected enumera los destinatarios a los que no se envió, cada uno con un rcpt y un reason. Una llamada puede tener éxito aunque se rechacen algunos destinatarios o incluso todos, así que compruebe siempre rejected:

reasonSignificado
invalid_recipientLa dirección no es válida
suppressed:<scope>:<reason>La dirección está en una lista de supresión, por ejemplo suppressed:global:hard_bounce
sandbox_recipient_not_verifiedEl flujo está en el sandbox y el destinatario no está permitido
rate_limited_hourly, rate_limited_sandbox_or_hourlySe ha agotado el límite por hora (o el límite diario del sandbox)
monthly_quota_exceededSe ha agotado el volumen mensual y no se permite excedente
enqueue_failedNo se pudo poner el mensaje en cola. No se descuenta de su cuota. Vuelva a intentarlo.

Ejemplo en Python con requests:

python
import requests

resp = requests.post(
    "https://api.tm.yeapcloud.net/v1/send",
    headers={"Authorization": "Bearer ytm_your_api_key"},
    json={
        "from": "Example <noreply@example.com>",
        "to": "alice@example.org",
        "subject": "Welcome",
        "html": "<p>Welcome aboard!</p>",
        "text": "Welcome aboard!",
        "category": "welcome",
    },
    timeout=30,
)
resp.raise_for_status()
result = resp.json()
print(result["message_ids"], result["rejected"])

Envío masivo: POST /v1/batch

Envíe hasta 500 mensajes en una sola solicitud. Cada elemento tiene los mismos campos que /v1/send.

json
{
  "messages": [
    {"from": "noreply@example.com", "to": "a@example.org", "subject": "Hi A", "text": "Hello A"},
    {"from": "noreply@example.com", "to": "b@example.org", "subject": "Hi B", "text": "Hello B"}
  ]
}

La respuesta contiene un resultado por mensaje, en el mismo orden:

json
{
  "results": [
    {"index": 0, "message_ids": ["01JAQ..."], "rejected": []},
    {"index": 1, "error": {"code": "invalid_request", "message": "subject is required (single line)"}, "rejected": []}
  ]
}

Consultar mensajes: GET /v1/messages

Parámetro de consultaDescripción
statusFiltrar por estado: queued, delivered, deferred, bounced, complained, rejected o failed
toFiltrar por dirección de destinatario
sinceSolo mensajes creados en esta fecha y hora o después, como 2026-10-01T00:00:00Z
limitResultados por página, 1–100 (50 de forma predeterminada)
beforePara la página siguiente, pase el valor next_before de la respuesta anterior

La respuesta es {"data": [...], "next_before": "..."}. next_before es null en la última página. Los mensajes se conservan durante 30 días.

GET /v1/messages/{id} devuelve un mensaje y sus eventos:

json
{
  "id": "01JAQ3Z9V8K4M2N6P7R5S1T0XW",
  "stream_id": 12,
  "source": "api",
  "to": "alice@example.org",
  "from": "Example <noreply@example.com>",
  "subject": "Welcome",
  "category": "welcome",
  "tags": [],
  "status": "delivered",
  "smtp_code": 250,
  "smtp_response": "250 2.0.0 OK",
  "opened_at": null,
  "clicked_at": null,
  "unsubscribed_at": null,
  "created_at": "2026-10-20 10:15:02",
  "updated_at": "2026-10-20 10:15:04",
  "events": [
    {"type": "delivered", "at": "2026-10-20 10:15:04", "rcpt": "alice@example.org", "smtp_code": 250, "mx": "mx.example.org"}
  ]
}

Supresiones: /v1/suppressions

Estos endpoints gestionan la lista de supresión del flujo de la clave de API.

SolicitudCuerpo o consultaRespuesta
GET /v1/suppressionsConsulta email (opcional), limit (1–500, 100 de forma predeterminada), offset{"data": [{"id", "scope", "email", "reason", "category", "note", "created_at"}]}
POST /v1/suppressions{"email": "..."} o {"emails": [...]} (hasta 1,000), category opcional{"added": 2, "invalid": []}
DELETE /v1/suppressions{"email": "..."}, category opcional (en el cuerpo o en la consulta){"removed": 1}

Las direcciones añadidas a través de la API tienen el motivo manual. Las supresiones de toda la cuenta y las globales no se pueden modificar con la API. Consulte Supresiones y bajas.

Relacionado

¿Le resultó útil esta página?