Una integración de API de correo fiable depende sobre todo de lo que ocurre cuando algo sale mal. El camino feliz es una sola solicitud HTTP. Los casos difíciles son un timeout en el que no sabe si el mensaje fue aceptado, un worker que se cae a mitad de un lote y un bucle de reintentos que convierte una breve interrupción en una avalancha. Esta guía nos ofrece un conjunto de patrones que logran que cada correo se envíe exactamente una vez o, en el peor caso, una vez de forma predecible, sea cual sea el endpoint del proveedor al que llame.
Describimos los patrones de forma genérica para que funcionen con cualquier API de correo HTTP, incluida MigoSMTP. Cuando una función concreta importe, como un encabezado de idempotencia, un endpoint por lotes o un límite de frecuencia, consulte su cuenta de MigoSMTP o la documentación de la API para conocer los detalles exactos en lugar de darlos por supuestos. Si todavía está eligiendo entre protocolos, lea primero SMTP o API: cómo elegir.
Por qué los envíos de correo fallan de formas que otras llamadas a API no
La mayoría de las llamadas a una API pueden repetirse sin consecuencias. El correo no. Una segunda llamada para crear un usuario normalmente falla con un conflicto, pero una segunda llamada para enviar un recibo envía alegremente un segundo recibo. El cliente ve dos mensajes, soporte recibe una queja, y un restablecimiento de contraseña enviado dos veces puede invalidar el primer código que la persona está leyendo.
El problema de fondo es el resultado desconocido. Su cliente envía la solicitud, el servidor la acepta y la respuesta se pierde por una caída de red o un timeout. Desde su lado, esto es idéntico a una solicitud que nunca llegó. Si reintenta, puede duplicar. Si no reintenta, puede perder el mensaje. Todos los patrones que siguen existen para resolver esa ambigüedad.
| Fallo | Lo que sabe | Riesgo si se gestiona de forma ingenua |
|---|---|---|
| Conexión rechazada o fallo de DNS | La solicitud nunca llegó a la API | Es seguro reintentar; el único riesgo es una tormenta de reintentos |
| Timeout de lectura después de enviar la solicitud | Nada sobre la aceptación | Reintentar sin clave de deduplicación puede duplicar el envío |
| 429 Too Many Requests | La API rechazó la llamada por motivos de ritmo | Un reintento inmediato agrava la presión |
| 5xx de la API o de una pasarela | Normalmente no se aceptó, pero no está garantizado | En algunos casos, la misma ambigüedad que un timeout |
| Error de validación 400 o 422 | La solicitud en sí es incorrecta | Reintentar sin fin desperdicia capacidad y oculta un error |
| Caída del worker después de la llamada a la API | Aceptado, pero nunca lo registró | El trabajo se vuelve a entregar y el correo se envía otra vez |
Claves de idempotencia y prevención de envíos duplicados
Una operación idempotente produce el mismo resultado sin importar cuántas veces se realice. Muchas API HTTP permiten pasar una clave de idempotencia, habitualmente en un encabezado, de modo que una solicitud repetida con la misma clave devuelve el resultado original en lugar de crear un recurso nuevo. La IETF tiene un borrador activo para un campo de encabezado estándar Idempotency-Key, lo que demuestra lo extendida que está la idea. Si MigoSMTP admite un encabezado de este tipo, y durante cuánto tiempo se recuerda una clave, debe confirmarse en la documentación de la API de MigoSMTP. Aquí no lo damos por supuesto.
La buena noticia es que no tiene que esperar a que el servidor lo admita. Puede construir la misma garantía de su lado con una tabla de deduplicación. La idea clave es que su aplicación decide la identidad de un correo antes de hablar con la red.
Elija una clave de deduplicación determinista
Una buena clave se deriva del evento de negocio, no se genera en el momento del envío. Use algo como order-1042-shipped o user-77-password-reset-2026-10-15T09:14. Un UUID aleatorio creado dentro del worker no sirve, porque un trabajo reentregado crearía uno nuevo. Incluya el tipo de mensaje para que un recibo y un aviso de envío del mismo pedido no colisionen, e incluya un intervalo de tiempo o un contador solo cuando los envíos repetidos sean legítimos, por ejemplo en un resumen diario.
Hágala cumplir con una restricción de unicidad
Las comprobaciones en la aplicación, como consultar y luego insertar, son propensas a condiciones de carrera. Ponga un índice único sobre la clave y deje que la base de datos resuelva los empates. El primer escritor gana y crea el registro de envío. Cualquier intento posterior recibe un error de restricción o encuentra la fila existente y lee su estado.
CREATE TABLE email_sends (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
dedupe_key VARCHAR(190) NOT NULL,
to_address VARCHAR(320) NOT NULL,
template VARCHAR(80) NOT NULL,
payload_json JSON NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'pending',
attempts INT NOT NULL DEFAULT 0,
next_try_at DATETIME NULL,
message_id VARCHAR(255) NULL,
last_error TEXT NULL,
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL,
UNIQUE KEY uq_dedupe (dedupe_key)
);
Los estados que usamos son pending, sending, accepted, failed y unknown. Accepted significa que la API devolvió éxito y usted guardó el ID de mensaje. Unknown significa que se hizo una llamada y el resultado no es seguro, algo que tratamos en la sección de reintentos. Si la API sí admite una clave de idempotencia, pase también ahí la misma clave de deduplicación, para que ambas capas coincidan. Considere el soporte del lado del servidor como una segunda red de seguridad, no como un sustituto.
El patrón outbox: enviar solo lo que se confirmó
El error clásico es así: su código guarda un pedido, luego llama a la API de correo y después retorna. Si la llamada a la API falla, el pedido existe sin correo. Si llama primero a la API y la confirmación de la base de datos falla, el cliente recibe una confirmación de un pedido que no existe. Dos sistemas no pueden actualizarse en una sola transacción, así que cambiamos el problema.
Con el patrón outbox, la solicitud de correo es simplemente otra fila escrita en la misma transacción que el cambio de negocio. O se confirman ambas o ninguna. Después, un proceso independiente entrega las filas del outbox a la API. La entrega se convierte en un trabajo en segundo plano reintentable, y la base de datos es la única fuente de verdad sobre lo que debe enviarse.
- Transacción: inserte el pedido y la fila de email_sends juntos, con el estado pending.
- Confirmación: solo después de la confirmación algo se hace visible para el proceso de envío.
- Reclamación: un worker selecciona las filas pending que ya les toca y las marca como sending, usando bloqueo de filas para que dos workers nunca tomen la misma.
- Llamada a la API: envíe la solicitud y luego registre el resultado y el ID de mensaje en la fila.
- Conciliación: un trabajo periódico busca filas atascadas en sending o unknown y las resuelve.
Puede alimentar al worker consultando la tabla cada pocos segundos, o publicando en una cola después de la confirmación. La consulta periódica es más sencilla y tiene menos piezas móviles. Una cola ayuda cuando el volumen es alto, pero conserve la tabla como registro de verdad, porque las colas pueden reentregar o perder mensajes y la tabla le permite preguntar qué pasó con este correo.
Colas en su aplicación: workers, concurrencia y orden
No llame a la API de correo dentro de la solicitud web salvo que tenga una razón de peso. Una respuesta lenta de cualquier tercero se convierte entonces en un pago lento, y un pico de registros se convierte en un pico de conexiones abiertas. Responda al usuario en cuanto se confirme la fila del outbox y deje que los workers en segundo plano hagan la entrega.
- Limite la concurrencia. Un número fijo de workers, cada uno con un pequeño pool de conexiones HTTP, le da un techo predecible de solicitudes por segundo. El paralelismo sin límite es la forma en que una aplicación alcanza por accidente el límite de una API.
- Separe las colas por urgencia. Los restablecimientos de contraseña y los códigos de un solo uso nunca deben esperar detrás de un boletín. Use colas o prioridades distintas, como se explica en separar los flujos transaccionales y de marketing.
- Haga idempotentes los trabajos. Suponga que cada trabajo puede entregarse dos veces. El primer paso de un trabajo es cargar la fila y salir si el estado ya es accepted.
- No dependa del orden. Los reintentos y los workers en paralelo reordenan los mensajes. Si el orden importa, por ejemplo verificación antes de bienvenida, modélelo como una dependencia en sus datos, no como orden de cola.
- Haga caducar el correo obsoleto. Un código de inicio de sesión entregado después de veinte minutos es peor que ninguno. Asigne una caducidad a las filas sensibles al tiempo y márquelas como expiradas en lugar de enviarlas.
Mantenga las cargas pequeñas. Guarde el nombre de la plantilla y las variables, o el contenido final ya renderizado, pero no archivos adjuntos grandes dentro de los mensajes de la cola. Haga referencia a los archivos almacenados por ID, de acuerdo con los límites explicados en nuestra guía de límites de tamaño y MIME.
Timeouts y clasificación de reintentos
Cada llamada HTTP necesita timeouts explícitos. Un cliente sin timeout esperará mucho más de lo que a una persona le importa y ocupará un hueco de worker todo ese tiempo. Defina un timeout de conexión corto, a menudo de uno o dos segundos, y un timeout total lo bastante largo para una respuesta normal pero lo bastante corto para fallar rápido. Elija los valores a partir de su propia latencia medida y de la orientación de su documentación de la API de MigoSMTP, no de una cifra en una entrada de blog.
Cuando termina una llamada, coloque el resultado en uno de tres grupos. Esta clasificación es el corazón de la integración.
| Resultado | Ejemplos | Acción |
|---|---|---|
| Aceptado | 2xx con un ID de mensaje | Guardar el ID, marcar como accepted y parar |
| Rechazado definitivamente, no reintentar | 400, 401, 403, 404, 422, otros 4xx que describen su solicitud | Marcar como failed, registrar el cuerpo del error, alertar si se repite; corregir código, credenciales o datos |
| Reintentar más tarde, misma clave de deduplicación | 429, 500, 502, 503, 504, errores de conexión, errores de DNS | Esperar con backoff y reintentar; respetar Retry-After |
| Resultado desconocido | Timeout de lectura, conexión restablecida tras el envío | Reintentar solo con la misma clave de deduplicación, o conciliar primero |
La semántica HTTP de estos códigos, incluido el encabezado Retry-After, se define en la RFC 9110, y la RFC 6585 define el 429. Tenga en cuenta la diferencia con SMTP. En SMTP, las respuestas 4xx son temporales y las 5xx permanentes, algo que tratamos en nuestra guía de códigos de rebote SMTP. En una API HTTP los papeles son distintos: 5xx significa que el servicio tuvo un problema y 4xx significa que su solicitud tuvo uno. No mezcle ambos modelos. Un HTTP 400 nunca es un fallo temporal de correo.
Backoff con jitter
Los retardos de reintento deben crecer de forma exponencial e incluir aleatoriedad, para que mil workers que fallaron a la vez no vuelvan todos a la vez. Un enfoque habitual es un retardo base que se duplica en cada intento, limitado por un máximo, con una fracción aleatoria aplicada. Si la respuesta incluye Retry-After, úselo como mínimo. Fije un número máximo de intentos o una antigüedad máxima, pasados los cuales la fila pasa a failed y genera una alerta. Nuestra guía sobre límites de frecuencia, reintentos y backoff profundiza en la estrategia.
import random, time
RETRY_STATUS = {429, 500, 502, 503, 504}
def next_delay(attempt, retry_after=None, base=2.0, cap=300.0):
delay = min(cap, base * (2 ** attempt))
delay = random.uniform(delay / 2, delay)
if retry_after is not None:
delay = max(delay, float(retry_after))
return delay
def deliver(row, client):
try:
resp = client.post("/send", json=row.payload,
headers={"X-Dedupe-Key": row.dedupe_key},
timeout=(2, 15))
except (ConnectionError, TimeoutError):
return ("retry", next_delay(row.attempts))
if 200 <= resp.status_code < 300:
return ("accepted", resp.json().get("id"))
if resp.status_code in RETRY_STATUS:
ra = resp.headers.get("Retry-After")
return ("retry", next_delay(row.attempts, ra))
return ("failed", resp.text[:500])
El nombre del encabezado de este ejemplo es inventado, solo para ilustrar. Use el que especifique la documentación de la API de MigoSMTP, o base su protección únicamente en su propia tabla si no existe tal encabezado.
Gestión de respuestas y almacenamiento de los ID de mensaje
Una respuesta de éxito no es el final de la historia, es el comienzo del seguimiento. Guarde de inmediato el ID de mensaje de la respuesta en su registro de envío, en el mismo paso que marca la fila como accepted. Así los eventos de webhook de entrega, rebote y queja pueden unirse a él. La fiabilidad de esa segunda mitad se trata en cómo manejar los webhooks de correo de forma fiable.
- Conserve durante un tiempo corto el cuerpo bruto de la respuesta de la API. Es muy valioso para depurar.
- Registre marcas de tiempo de creación, primer intento, aceptación y último evento. Los intervalos entre ellas muestran dónde se producen los retrasos.
- Entienda qué significa «aceptado». Una respuesta 2xx de una API de correo normalmente significa que el servicio puso el mensaje en cola para su entrega, no que el servidor del destinatario lo aceptara. La entrega final se informa más tarde mediante eventos.
- No analice los mensajes de error como lógica. Use códigos de estado y cualquier código de error documentado, y trate el texto libre como información para personas.
- Indexe la columna del ID de mensaje para que soporte pueda ir de un ID en un log al registro de un cliente con una sola consulta.
Oculte secretos y datos personales en los logs. Registre la clave de deduplicación, el ID de envío, el estado y el ID de mensaje, pero no las claves de API ni los cuerpos completos de los mensajes. Las claves deben almacenarse y rotarse como se describe en la seguridad de las claves de API.
Lotes y envíos masivos
Enviar a muchos destinatarios es una carga de trabajo distinta a enviar un recibo. Ahora debe gestionar el rendimiento, la memoria y la equidad respecto al resto del tráfico. Algunas API de correo ofrecen un endpoint por lotes que acepta muchos mensajes en una sola solicitud, y otras esperan un mensaje por solicitud con muchas llamadas concurrentes. Consulte su cuenta de MigoSMTP o la documentación de la API para saber qué está disponible y cuáles son los límites de destinatarios por solicitud antes de diseñar en torno a una u otra opción.
- Divida la audiencia en bloques. Lea los destinatarios por páginas desde la base de datos, no como una lista gigante en memoria. Cree filas de envío por destinatario y deje que los workers las procesen.
- Personalice por destinatario. Evite poner muchos destinatarios en To o Cc. Cada persona debe recibir su propio mensaje, con su propio enlace de baja y sus propios datos de seguimiento.
- Module el envío. Reparta las campañas grandes en una ventana de tiempo en lugar de soltarlo todo de golpe. Modular también protege su reputación, sobre todo en dominios nuevos, como se describe en la guía de calentamiento.
- Haga la campaña reanudable. Como cada destinatario tiene una fila con una clave de deduplicación única, como campaign-318-user-9001, puede detener y reiniciar un envío en cualquier punto sin enviar duplicados.
- Gestione los fallos parciales. Si una llamada por lotes puede tener éxito para unos mensajes y fallar para otros, guarde resultados por mensaje. Nunca marque un lote entero como aceptado o fallido con un solo código de estado, salvo que la documentación diga que funciona así.
No se salte lo básico de las listas: el envío masivo mediante una API no cambia las reglas de consentimiento, supresión y baja. Filtre las direcciones suprimidas antes de crear las filas de envío, siguiendo el enfoque de nuestra guía de listas de supresión.
Ejemplo práctico: una interrupción, dos diseños
Este es un ejemplo inventado con cifras redondas. Una tienda en línea envía una confirmación por cada pedido. En una tarde de mucho movimiento crea 6.000 pedidos en una hora, y la API de correo sufre un período de 4 minutos de respuestas lentas y errores 503 intermitentes.
| Paso | Diseño ingenuo | Outbox con clave de deduplicación |
|---|---|---|
| Se crea el pedido | La solicitud llama directamente a la API | La solicitud escribe el pedido y la fila de envío, y responde de inmediato |
| API lenta durante 4 minutos | El pago espera con un timeout largo, algunos clientes ven errores y vuelven a pulsar Pagar | El pago no se ve afectado; las filas esperan en pending |
| Timeout en 150 llamadas | El código reintenta de inmediato; muchos de esos mensajes ya habían sido aceptados | Filas marcadas como unknown; se reintentan más tarde con la misma clave de deduplicación |
| Resultado | 150 pedidos con aproximadamente 2 confirmaciones cada uno, más pedidos duplicados por doble clic | Unos 150 mensajes retrasados unos minutos; cero duplicados |
| Impacto en soporte | Decenas de tickets preguntando qué correo es el correcto | Ninguno; saltó y se resolvió la alerta de antigüedad de la cola |
Con 6.000 pedidos en la hora, el promedio es de 100 por minuto, de modo que una lentitud de 4 minutos deja una acumulación de unas 400 filas. Si los workers pueden enviar 300 por minuto una vez que la API se recupera, la acumulación se despeja en unos 2 minutos (400 filas divididas entre los 200 por minuto de capacidad sobrante por encima de los 100 por minuto de nuevas llegadas). Vale la pena hacer esta aritmética para su propio sistema: la capacidad sobrante de sus workers decide la rapidez de la recuperación, y el límite de concurrencia decide si la recuperación se mantiene dentro de los límites de su cuenta.
Gestión de los límites de frecuencia
Los límites de frecuencia adoptan formas como solicitudes por segundo, mensajes por día, conexiones concurrentes y destinatarios por solicitud. Cuáles se aplican a su cuenta, y sus valores exactos, figuran en su cuenta de MigoSMTP o en la documentación de la API. No los adivine. Construya su cliente de modo que los números sean configuración, no constantes en el código.
- Use un token bucket o un retardo fijo entre solicitudes en cada worker, con un tope global entre todos los workers.
- Ante un 429, deje de enviar desde ese worker durante el período de Retry-After, o durante un retardo de backoff si no se indica ninguno. No se limite a reintentar la misma llamada.
- Vigile el éxito lento. Una tendencia creciente de latencia suele llegar antes que los errores, y es una señal para reducir la concurrencia.
- Use un circuit breaker. Tras una racha de fallos, pause las llamadas durante una ventana corta y luego pruebe con una sola solicitud antes de reanudar a plena velocidad.
- Tenga presentes los límites del lado receptor. La aceptación del proveedor es solo el primer salto. Los proveedores de buzones aplican sus propios límites, tratados en nuestra guía de requisitos para remitentes masivos.
Degradación controlada cuando la API no está disponible
Cualquier servicio externo dejará de estar disponible alguna vez. Decida con antelación qué hace su producto, para que la respuesta no se improvise durante un incidente.
| Tipo de correo | Comportamiento sugerido durante una interrupción |
|---|---|
| Restablecimiento de contraseña, código de un solo uso | Encolar con una caducidad corta; mostrar en pantalla que el mensaje puede retrasarse y ofrecer reenvío tras un período de espera |
| Confirmación de pedido o pago | Encolar y entregar con retraso; mostrar también la confirmación en la página del pedido |
| Notificaciones de cuenta | Encolar y entregar con retraso; considerar combinar varias en una sola |
| Boletines y campañas | Pausar la campaña y reanudarla más tarde; nunca apresurarse para ponerse al día |
| Alertas internas | Recurrir a otro canal, como el chat, o a un segundo proveedor |
Configure alertas sobre la profundidad de la cola y sobre la antigüedad de la fila pendiente más antigua, no solo sobre el número de errores. Una cola creciente sin errores sigue significando que hay clientes esperando. Fije un tope a la cola para que la memoria y el almacenamiento no puedan crecer sin límite, y decida qué se descarta primero si se alcanza el tope. Si diseña un segundo proveedor como respaldo, recuerde el trabajo que supone calentar y autenticar un segundo camino, como se describe en nuestra guía de migración.
Pruebas de la integración
Las pruebas que solo comprueban una respuesta 200 no lo protegerán. El comportamiento importante es lo que ocurre ante un fallo, así que facilite provocarlo. Ejecute su cliente contra un servidor simulado o un sandbox al que pueda indicarse que responda con lentitud, devuelva 429 con Retry-After, devuelva 503, corte la conexión tras leer la solicitud o devuelva un cuerpo mal formado. Use un capturador de correo para verificar el contenido, siguiendo nuestra guía del entorno de staging.
- Prueba de trabajo duplicado: encole el mismo trabajo dos veces y compruebe que solo una solicitud llega a la API simulada.
- Prueba de caída: detenga un worker después de la llamada a la API y antes de la actualización de la base de datos, y compruebe que el conciliador resuelve la fila sin un segundo envío.
- Prueba de timeout: haga que el simulador acepte la solicitud y luego se detenga, y compruebe que la fila termina como accepted exactamente una vez.
- Prueba de mensaje venenoso: envíe una carga que devuelva 422 y confirme que pasa a failed tras un solo intento, con el error guardado.
- Prueba de carga: ejecute una ráfaga realista contra staging para confirmar que los límites de concurrencia y el backoff se comportan como se diseñó.
Lista de verificación previa al lanzamiento
- Cada correo tiene una clave de deduplicación determinista y un índice único la hace cumplir.
- Las filas de envío se escriben en la misma transacción que el evento de negocio (outbox).
- El soporte de un encabezado de idempotencia está confirmado en la documentación de la API de MigoSMTP, y de todos modos se usa nuestra propia tabla.
- Los workers, no las solicitudes web, llaman a la API, con concurrencia acotada.
- Los timeouts de conexión y total están definidos en cada llamada.
- Las respuestas se clasifican: accepted, retry, failed, unknown. Otras respuestas 4xx nunca se reintentan a ciegas.
- El backoff tiene jitter, un tope, un número máximo de intentos y respeta Retry-After.
- Los ID de mensaje se guardan en las filas de envío y están indexados.
- Los envíos masivos se dividen en bloques, se modulan y son reanudables, con filtrado de supresión antes de crear las filas.
- Los límites de frecuencia son configuración, tomada de su cuenta o de la documentación de la API.
- Existen alertas para la antigüedad de la fila pendiente más antigua, el número de fallos y la tasa de 429.
- Las pruebas de fallo de duplicados, caídas, timeouts y 429 pasan en staging.
¿Quiere una segunda opinión sobre el diseño de sus envíos? Cuéntenos cómo envía correo hoy su aplicación y dónde le preocupan los reintentos o los duplicados, y le ayudaremos a planificar una integración segura.
Lecturas adicionales y fuentes
- RFC 9110: Semántica HTTP (códigos de estado, Retry-After, métodos idempotentes)
- RFC 6585: Códigos de estado HTTP adicionales (429 Too Many Requests)
- RFC 5321: Protocolo simple de transferencia de correo (SMTP)
- Borrador de la IETF: El campo de encabezado HTTP Idempotency-Key
- Amazon Builders Library: Timeouts, reintentos y backoff con jitter
Preguntas frecuentes
¿Qué es una clave de idempotencia en una API de correo?
Es un valor único que se adjunta a una solicitud para que el servidor pueda reconocer una repetición de la misma solicitud y evitar hacer el trabajo dos veces. En el caso del correo, significa que un reintento tras un timeout no produce una segunda copia del mensaje. Si MigoSMTP admite un encabezado de idempotencia, y cómo lo hace, debe confirmarse en la documentación de la API de MigoSMTP. En cualquier caso, puede obtener la misma protección con su propia tabla de deduplicación.
Si la API admite idempotencia, ¿sigo necesitando mi propia tabla de deduplicación?
Sí, lo recomendamos. La idempotencia del lado del servidor suele cubrir solo una ventana limitada y únicamente las solicitudes que llegan a la API. Su propia tabla también detiene los trabajos duplicados, los disparos duplicados de webhooks y los doble clic en capas anteriores, y le ofrece un registro de auditoría de lo que pretendía enviar.
¿Es seguro reintentar después de un timeout?
Solo si cuenta con una estrategia de deduplicación. Un timeout significa que no sabe si la API aceptó el mensaje. Sin una clave de idempotencia ni una consulta por su propia referencia, un reintento puede enviar el correo dos veces. Con una de ellas, el reintento es seguro.
¿Qué códigos de estado HTTP debo reintentar?
Reintente los fallos de red, los timeouts, 429 Too Many Requests y los errores de servidor 5xx, usando backoff exponencial con jitter y respetando cualquier encabezado Retry-After. No reintente otros errores 4xx como 400, 401, 403 o 422, porque la misma solicitud fallará de la misma manera hasta que cambie algo.
¿Qué es el patrón outbox?
Se escribe la solicitud de correo en una tabla dentro de la misma transacción de base de datos que el cambio de negocio, y después un proceso independiente lee las filas no enviadas y llama a la API. Esto elimina el desfase en el que la confirmación de la base de datos se realiza pero la llamada de correo falla, o al revés.
¿Debo enviar los correos desde la solicitud web o desde una cola?
Desde una cola, para casi todo. Una cola protege la latencia de cara al usuario, permite reintentar con seguridad y le deja controlar la frecuencia. La excepción es una herramienta interna muy sencilla en la que un envío fallido puede mostrarse sin más a la persona que lo desencadenó.
¿Cómo debo enviar una campaña grande a través de una API?
Divida los destinatarios en lotes, limite la concurrencia, respete los límites documentados y Retry-After, y reparta el envío a lo largo del tiempo. Consulte su cuenta de MigoSMTP o la documentación de la API para conocer los límites exactos y si existe un endpoint por lotes. En dominios o IP nuevos, siga además un plan de calentamiento.
¿Por qué guardar el ID de mensaje que devuelve la API?
Es la clave de unión entre su registro de envío y los eventos posteriores, como los webhooks de entrega, rebote y queja. Sin él, preguntas de soporte como «¿recibió este cliente el recibo?» se convierten en conjeturas.
¿Cómo pruebo una integración de correo sin enviar correo real?
Ejecute el cliente de la API contra un servidor simulado o un sandbox que pueda devolver respuestas lentas, 429 y 5xx bajo demanda, y use un capturador de correo para verificar el contenido. Compruebe su tabla de envíos, no solo las llamadas HTTP. Nuestra guía de staging describe configuraciones seguras.