Ingeniería · 21 de septiembre de 2026
Claves de idempotencia para API de correo
Evite correos duplicados durante los reintentos de red implementando claves de idempotencia. Aprenda a gestionar los fallos de sistemas distribuidos sin saturar de spam a sus usuarios.
El problema de los correos duplicados
Los correos duplicados se producen cuando un cliente envía una solicitud, el servidor la procesa, pero la red falla antes de que el cliente reciba la respuesta correcta. El cliente, al ver un tiempo de espera agotado o un error 5xx, reintenta la solicitud. Sin idempotencia, el servidor trata el reintento como una solicitud nueva y vuelve a enviar el correo. Las claves de idempotencia lo evitan porque permiten al servidor reconocer una solicitud repetida y devolver el resultado original sin volver a ejecutar el efecto secundario.
Para un ingeniero responsable de la cola de incidentes, no hay nada peor que una "tormenta de correos duplicados". Suele ocurrir durante una caída parcial de un proveedor upstream o un interbloqueo de la base de datos que ralentiza las respuestas. Su lógica de reintentos, diseñada para aportar confiabilidad, se convierte en un arma que llena de spam a sus usuarios y daña su reputación de remitente.
Por qué fallan los reintentos sin idempotencia
En un sistema distribuido, cualquier llamada a la API tiene tres puntos de fallo:
- La solicitud nunca llega al servidor.
- El servidor procesa la solicitud, pero la respuesta se pierde.
- El servidor se cae a mitad del proceso.
Si reintenta en el caso 1, no hay problema. Si reintenta en el caso 2, envía un duplicado. Si reintenta en el caso 3, puede enviar un duplicado según el punto en que se produjo el fallo.
Enviar un correo es un efecto secundario externo. A diferencia de actualizar el nombre de un usuario en una base de datos (que es idempotente por naturaleza si usa SET name = 'Alice'), enviar un correo es una acción acumulativa. Cada llamada a un endpoint send crea un mensaje nuevo en el mundo. Para hacerla idempotente, debe introducir un identificador único para la intención de envío, conocido como clave de idempotencia.
Implementación de claves de idempotencia
Una clave de idempotencia es un valor único (normalmente un UUID v4) generado por el cliente y enviado en un encabezado de la solicitud. El servidor usa esta clave para seguir el estado de la solicitud.
El flujo en el servidor
- Recepción de la solicitud: el servidor comprueba si existe el encabezado
Idempotency-Key. - Consulta: el servidor busca esa clave en un almacén de acceso rápido (como Redis).
- Acierto de caché: si la clave existe, el servidor devuelve de inmediato la respuesta almacenada sin llamar al motor de entrega de correo.
- Fallo de caché: el servidor bloquea la clave, procesa el envío del correo, almacena la respuesta y la devuelve al cliente.
- Caducidad: la clave caduca tras un periodo (por ejemplo, 24 horas) para que la base de datos no crezca indefinidamente.
Ejemplo concreto de payload
Así debería ser una solicitud al usar una API como SendHQ:
POST /v1/send
Host: api.sendhq.cc
Content-Type: application/json
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Authorization: Bearer YOUR_API_KEY
{
"to": "user@example.com",
"template_id": "welcome-email",
"variables": {
"name": "Alex"
}
}
Gestión de los casos de error
No todos los reintentos deben tratarse igual. Debe distinguir entre errores del cliente y errores del servidor.
- Errores 4xx: si el servidor devuelve un 400 (Bad Request) o un 422 (Unprocessable Entity), la solicitud no es válida. Reintentar con la misma clave debería devolver el mismo error 4xx. No cambie el payload reutilizando la clave, ya que eso genera un conflicto.
- Errores 5xx: si el servidor devuelve un 500 o un 503, el cliente debería reintentar. Si el servidor ya había entregado correctamente el correo al MTA (agente de transferencia de correo), la clave de idempotencia garantiza que el reintento devuelva un 200 OK en lugar de enviar un segundo correo.
- Solicitudes simultáneas: si dos solicitudes idénticas con la misma clave llegan exactamente en el mismo milisegundo, el servidor debería devolver un 409 Conflict a la segunda para indicar que la primera aún se está procesando.
Idempotencia para agentes de IA
Los agentes de IA (que usan servidores MCP o tarjetas A2A) introducen una nueva capa de riesgo. Los LLM pueden no ser deterministas y pueden lanzar la misma llamada a una herramienta varias veces si perciben un fallo en el bucle.
Al crear integraciones preparadas para agentes, nunca debería permitir que un agente lance una acción send sin un paso de aprobación o sin una clave de idempotencia determinista generada por el orquestador. El orquestador debería asignar la intención del agente (por ejemplo, "Enviar el informe semanal a Bob") a una clave estable basada en el ID del informe y la fecha. Así se evita que el agente envíe por error el mismo informe cinco veces porque "creyó" que la primera llamada había fallado.
El costo del fallo: comparativa de proveedores
Si no implementa la idempotencia, no solo molesta a sus usuarios: también desperdicia dinero. Aunque algunos proveedores son más baratos, el costo de los duplicados crece rápidamente.
Según las páginas de precios oficiales (a septiembre de 2026):
- Amazon SES: cuesta 0.10 USD por cada 1.000 correos a la carta (precios de Amazon SES). Los nuevos planes escalonados introducidos el 21 de julio de 2026 incluyen Essentials (0.16 USD por cada 1.000), Pro (0.22 USD por cada 1.000 más 105 USD al mes por región) y Enterprise (0.23 USD por cada 1.000 más 500 USD al mes).
- Resend: el plan gratuito incluye 3.000 correos al mes con un máximo de 100 al día. Pro cuesta 20 USD al mes por 50.000 correos, con excedentes a 0.90 USD por cada 1.000 (precios de Resend).
- SendGrid: el plan gratuito es ahora una prueba de 60 días, y los planes Essentials empiezan en 19.95 USD al mes (precios de SendGrid).
- Mailgun: cuesta 15 USD al mes por 10.000 correos, con excedentes de entre 1.80 y 1.10 USD por cada 1.000 (precios de Mailgun).
- Postmark: cuesta 15 USD al mes por 10.000 correos, con excedentes de entre 1.80 y 1.20 USD por cada 1.000 (precios de Postmark).
Para ponerlo en perspectiva, enviar 50.000 correos cuesta unos 5 USD con SES a la carta, frente a unos 66 USD con los planes de Postmark. Si un bucle de reintentos sin idempotencia multiplica por error su volumen por 10, la diferencia económica entre proveedores se convierte en una partida importante de su informe de incidentes.
Entregabilidad frente a aceptación
Es fundamental entender que la idempotencia solo resuelve el problema de la aceptación.
- Aceptación: la API acepta su solicitud y devuelve 200 OK. Aquí es donde actúan las claves de idempotencia.
- Entrega: la API entrega el correo al servidor receptor (por ejemplo, Gmail). Aquí es donde importan SPF y DKIM/DMARC.
- Llegada a la bandeja de entrada: el servidor receptor decide si el correo va a la bandeja de entrada o a la carpeta de spam.
Una clave de idempotencia garantiza que solo acepte la solicitud una vez. No garantiza que el correo se entregue ni que evite la carpeta de spam. Para asegurarse de que su infraestructura está bien configurada para la entrega, use herramientas como el Verificador de DNS de correo de SendHQ para comprobar sus registros.
Lista de comprobación de implementación para ingenieros
Si hoy está auditando su lógica de envío de correo, use esta lista:
- Generación de claves del lado del cliente: ¿Genera un UUID v4 para cada intención de correo única?
- Implementación del encabezado: ¿La clave se transmite en un encabezado estándar (por ejemplo,
Idempotency-Key) en lugar de en el cuerpo de la solicitud? - Capa de almacenamiento: ¿Tiene un TTL (Time To Live) en sus claves de idempotencia para evitar el crecimiento excesivo del almacenamiento?
- Bloqueo atómico: ¿Su servidor usa un bloqueo distribuido (como
SET NXen Redis) para evitar condiciones de carrera con la misma clave? - Almacenamiento en caché de respuestas: ¿Almacena la respuesta completa (código de estado y cuerpo) para devolverla al cliente en los reintentos?
- Salvaguardas para agentes: Si usa agentes de IA, ¿la clave la genera el orquestador del sistema en lugar del LLM?
Ejemplo de código: middleware de idempotencia en Node.js
Este es un ejemplo simplificado de cómo podría implementar esta lógica en un entorno Node.js con Redis.
const redis = require('redis');
const client = redis.createClient();
async function sendEmailHandler(req, res) {
const idempotencyKey = req.headers['idempotency-key'];
if (!idempotencyKey) {
return res.status(400).json({ error: 'Idempotency-Key header is required' });
}
// Try to acquire a lock and check for existing response
const cachedResponse = await client.get(`idempotency:${idempotencyKey}`);
if (cachedResponse) {
const { status, body } = JSON.parse(cachedResponse);
return res.status(status).json(body);
}
// Set a lock to prevent concurrent requests
const lock = await client.set(`lock:${idempotencyKey}`, 'true', 'NX', 'EX', 30);
if (!lock) {
return res.status(409).json({ error: 'Request is currently being processed' });
}
try {
// Actual email sending logic
const result = await emailProvider.send(req.body);
const responsePayload = {
status: 200,
body: result
};
// Cache the result for 24 hours
await client.set(`idempotency:${idempotencyKey}`, JSON.stringify(responsePayload), 'EX', 86400);
return res.status(200).json(result);
} catch (error) {
return res.status(500).json({ error: 'Internal Server Error' });
} finally {
await client.del(`lock:${idempotencyKey}`);
}
}
Conclusiones
La idempotencia no es un "extra deseable" para el correo transaccional; es un requisito para cualquier sistema que valore la experiencia de usuario y el control de costos. Al trasladar al cliente la responsabilidad de la unicidad y ofrecer en el servidor un mecanismo para controlarla, elimina el riesgo de envíos duplicados durante la inestabilidad de la red.
Tanto si crea un producto SaaS tradicional como un agente de IA autónomo, tratar el correo como un efecto secundario crítico garantiza que su sistema siga siendo confiable y sus usuarios, satisfechos. Si busca una API de correo pensada para desarrolladores que gestione esta complejidad, visite https://sendhq.cc.