↓Ir al contenido
  1. Qubyts/

Los correos promocionales deberían caducar

·9 mins

Un día abrí la pestaña de Promociones de Gmail y vi el contador: más de siete mil correos sin abrir. No los iba a abrir. Nunca. Y aun así ahí estaban, desde cupones que vencieron hace años hasta webinars a los que nunca entré.

Este es el primer episodio de El Refactor, la serie donde tomo algo que funciona mal en un producto digital, lo mido y propongo cómo lo cambiaría. Aquí van las cifras completas, cómo las saqué y de dónde viene cada dato.


Primero medí: estas son mis cifras #

Antes de opinar quería un sustento, así que escribí un script que revisa mi bandeja sin borrar ni mover nada (está completo al final del post). Esto encontró el 25 de octubre de 2026:

Dato Valor
Correos en Promociones 7,535
Sin leer 7,309 (97.0%)
Sin leer y con más de 30 días 7,172 (95.2%)
Sin leer y con más de 1 año 5,567 (73.9%)
Correo más antiguo 19 de mayo de 2020
Peso promedio por correo (muestra de 400) 64.9 KB
Espacio estimado ~477 MB
Remitente más frecuente (muestra de 400) 3.3% de los correos

El más viejo sobrevivió a una pandemia sin que nadie lo leyera.

Mi primera idea fue la obvia: me doy de baja de los que más me escriben y listo. Pero el remitente más frecuente apenas pasa del 3%. No hay un culpable. Son cientos de marcas mandando de poquito en poquito, y darte de baja una por una es como sacar agua de un barco con una cuchara.

Dos aclaraciones sobre cómo medí:

  • Los conteos son exactos, pero el peso y los remitentes salen de una muestra aleatoria de 400 correos. Revisar los más de 7 mil uno por uno se pasa del límite de 6 minutos de Apps Script, así que el espacio total es una estimación.
  • Gmail me marcaba 7,271 y el script 7,309. No es un error: Gmail cuenta conversaciones (tres correos en un hilo cuentan como uno) y el script cuenta mensajes. La diferencia fue la misma cada vez que medí.

El problema no es técnico: es de diseño #

Lo interesante no es cuántos correos tengo. Es por qué todo está armado para que se acumulen.

Mi sospecha: al remitente le conviene que su correo se quede. Un correo que sigue en tu bandeja es una marca que sigue visible: el día que buscas “zapatos”, ahí está su promoción. Que lo borres no le da nada. Esto no lo puedo medir, así que lo dejo como sospecha.

Lo que sí puedo medir es el costo, y ese lo pagas tú. Una cuenta gratuita de Google trae 15 GB compartidos entre Gmail, Drive y Fotos. Mis promociones se comen alrededor del 3%. Y si tu cuenta se llena, según la propia ayuda de Gmail, dejas de recibir correos: te los rebotan. El aviso de tu banco, la respuesta de esa entrevista de trabajo, todo de regreso al remitente. ¿La salida que te ofrecen? Pagar por más espacio.

Alguien va a decir “pues automatízalo”. Sí, es fácil. Pero ese es justo el problema: le estás pidiendo al usuario que limpie lo que alguien más ensució. La mayoría nunca va a configurar un filtro, y lo que pasa por defecto es lo que se queda.

¿Y la huella de carbono? #

Cuando eso se acumula en millones de bandejas, el costo deja de ser solo tuyo. Guardar correos consume energía. Quise ponerle número, con las cifras de la agencia ambiental de Francia (ADEME) que recopila Projet Celsius:

Paso Estimación baja Estimación alta
Supuesto de ADEME 0.24 g CO₂e por GB al año ~1 g CO₂e por MB, guardado 10 años en 6 copias
Mi bandeja (477 MB) ~0.11 g al año ~48 g al año
Medio mundo (~4,100 millones de bandejas como la mía) ~460 t al año ~196,000 t al año
Equivalente en autos (4.6 t CO₂ por auto al año, EPA) ~100 autos ~42,500 autos

Sí, el rango es ridículo: los dos métodos de la propia ADEME difieren unas 70 veces. Por eso la contaminación no es mi argumento principal. Pero tampoco es cero, y no me la estoy inventando.

Entonces, ¿quién paga qué? El remitente gana visibilidad. Tú pagas con tu espacio, tu atención y, si se llena, tu dinero. El planeta paga un poquito por cada bandeja. Todos los costos de un lado y ninguna responsabilidad del otro.

El refactor: que el correo sepa cuándo caduca #

La idea es simple: la fecha la pone quien envía, no tú. La tienda sabe cuándo vence su promoción, así que debería hacerse responsable de no dejar basura en tu bandeja.

Técnicamente es una sola línea en los encabezados del correo:

Expires: Sat, 31 Oct 2026 23:59:59 -0600

Encabezados de un correo con la línea Expires resaltada y cómo se vería en la bandeja con la etiqueta Caduca: 31 oct

Con tres reglas:

  1. La fecha la define el remitente en el encabezado Expires.
  2. Tiene límites: no puede ser anterior al día en que se envió ni más de nueve meses después. Cabe hasta una campaña de precalentamiento, pero nadie puede poner “vence en 2099” y saltarse la regla.
  3. Hay una espera: el día que vence, el correo se oculta. Cinco días después, se borra.

Lo curioso: la IETF ya está en esto #

Investigando descubrí que la IETF, el grupo que escribe los estándares de internet, tiene un documento casi igual: Updated Use of the Expires Message Header Field (draft-ietf-mailmaint-expires). Al momento de escribir esto ya fue aprobado y está en la fila para publicarse como estándar.

Pero hay una diferencia con mi idea: ellos dicen que tu cliente de correo no debería borrar nada por su cuenta, solo ocultar o restarle importancia a lo vencido, salvo que tú lo configures. ¿Por qué? Porque un spammer podría poner una fecha que ya pasó para que su correo desaparezca antes de que lo reportes. Y tienen razón. Por eso mi versión espera cinco días antes de borrar: te da tiempo de rescatarlo o reportarlo, y aun así la bandeja se limpia sola.

¿Cuánto cambiaría mi bandeja? #

Mis correos viejos no traen fecha de vencimiento, así que hice un ejemplo: si cada promoción hubiera traído una vigencia de 25 días, con los 5 de espera, todo lo que nunca abrí y tiene más de 30 días ya se habría ido.

Correos Espacio
Hoy 7,535 ~477 MB
Con la regla 363 ~23 MB

De siete mil quinientos a trescientos sesenta y tres. Sin mover un dedo.

Qué puedes hacer tú hoy #

Mientras el estándar llega a los clientes de correo, puedes simularlo a mano. En el buscador de Gmail pega esto:

category:promotions is:unread older_than:30d

Son las promociones que nunca abriste y que tienen más de un mes. Selecciónalas todas y bórralas. Van a la papelera, así que tienes 30 días para rescatar algo si te equivocas.

Y si quieres saber cuánto ocupa tu bandeja, corre el script de abajo. Tus números van a ser distintos a los míos, y esa es la idea.


¿Cuántos correos tienes tú en Promociones? Déjalo en los comentarios del video, tengo curiosidad de qué tan lejos está mi bandeja del promedio.

Fuentes #

El script #

Pégalo en un proyecto nuevo de Google Apps Script, agrega el servicio Gmail API y ejecuta auditarPromociones. Solo lee tu correo: no borra ni modifica nada.

/**
 * El Refactor – Auditoría de la bandeja de Promociones
 *
 * Cómo usarlo:
 * 1. Entra a https://script.google.com y crea un proyecto nuevo.
 * 2. Pega este código.
 * 3. En el panel izquierdo, "Servicios" (+) → agrega "Gmail API".
 * 4. Elige la función auditarPromociones y dale "Ejecutar". Acepta los permisos.
 * 5. Los resultados aparecen en el "Registro de ejecución".
 *
 * Solo LEE tu correo. No borra ni modifica nada.
 */

const TAMANO_MUESTRA = 400; // correos que se revisan a detalle para estimar peso y remitentes
const MOSTRAR_REMITENTES = false; // false = no imprime nombres de remitentes (para grabar en pantalla)

function auditarPromociones() {
  const inicio = Date.now();

  // 1. Conteos exactos
  const todos = listarIds_('category:promotions');
  const sinLeer = contar_('category:promotions is:unread');
  const sinLeerMes = contar_('category:promotions is:unread older_than:30d');
  const sinLeerAnio = contar_('category:promotions is:unread older_than:1y');
  const total = todos.length;

  // 2. Muestra aleatoria para peso y remitentes
  const muestra = muestrear_(todos, TAMANO_MUESTRA);
  let bytes = 0;
  const remitentes = {};
  muestra.forEach(id => {
    const m = Gmail.Users.Messages.get('me', id, { format: 'metadata', metadataHeaders: ['From'] });
    bytes += m.sizeEstimate || 0;
    const from = (m.payload.headers.find(h => h.name === 'From') || {}).value || 'desconocido';
    const nombre = from.replace(/<.*>/, '').replace(/"/g, '').trim() || from;
    remitentes[nombre] = (remitentes[nombre] || 0) + 1;
  });
  const promedioKB = muestra.length ? bytes / muestra.length / 1024 : 0;
  const totalMB = (promedioKB * total) / 1024;
  const sinLeerMB = (promedioKB * sinLeer) / 1024;

  // 3. El correo más antiguo (la lista viene de más nuevo a más viejo)
  let masAntiguo = 'n/d';
  if (total) {
    const viejo = Gmail.Users.Messages.get('me', todos[total - 1], { format: 'minimal' });
    masAntiguo = Utilities.formatDate(new Date(Number(viejo.internalDate)), Session.getScriptTimeZone(), 'yyyy-MM-dd');
  }

  // 4. Top remitentes (porcentaje de la muestra)
  const top = Object.entries(remitentes)
    .sort((a, b) => b[1] - a[1])
    .slice(0, 10)
    .map(([nombre, n], i) => `${i + 1}. ${nombre} — ${(100 * n / muestra.length).toFixed(1)}%`);

  const pct = n => total ? (100 * n / total).toFixed(1) + '%' : '0%';
  const reporte = [
    '===== AUDITORÍA DE PROMOCIONES =====',
    `Total en Promociones:            ${total.toLocaleString()}`,
    `Sin leer:                        ${sinLeer.toLocaleString()} (${pct(sinLeer)})`,
    `Sin leer y con más de 30 días:   ${sinLeerMes.toLocaleString()} (${pct(sinLeerMes)})`,
    `Sin leer y con más de 1 año:     ${sinLeerAnio.toLocaleString()} (${pct(sinLeerAnio)})`,
    `Correo más antiguo:              ${masAntiguo}`,
    '',
    `Peso promedio (muestra de ${muestra.length}): ${promedioKB.toFixed(1)} KB`,
    `Espacio estimado total:          ${totalMB.toFixed(0)} MB`,
    `Espacio estimado de los sin leer: ${sinLeerMB.toFixed(0)} MB`,
    '',
    ...(MOSTRAR_REMITENTES
      ? ['Remitentes más frecuentes (en la muestra):', ...top]
      : [`Remitente más frecuente: ${top.length ? top[0].split(' — ')[1] : 'n/d'} de la muestra`]),
    '',
    `Tiempo: ${((Date.now() - inicio) / 1000).toFixed(0)} s`
  ].join('\n');

  Logger.log(reporte);
}

function listarIds_(q) {
  const ids = [];
  let pageToken;
  do {
    const r = Gmail.Users.Messages.list('me', { q, maxResults: 500, pageToken });
    (r.messages || []).forEach(m => ids.push(m.id));
    pageToken = r.nextPageToken;
  } while (pageToken);
  return ids;
}

function contar_(q) {
  return listarIds_(q).length;
}

function muestrear_(arr, n) {
  if (arr.length <= n) return arr.slice();
  const copia = arr.slice();
  for (let i = copia.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [copia[i], copia[j]] = [copia[j], copia[i]];
  }
  return copia.slice(0, n);
}

El Refactor es una serie

Cada episodio toma algo que funciona mal en un producto digital, lo mide y propone cómo arreglarlo. Si quieres ver el siguiente, suscríbete al canal.

Suscribirme al canal →