El boletín en un nodo: archivo sqlite — 1.258 líneas, sin plataforma
Doble opt-in, baja en un clic y una CLI de envío sobre 1.258 líneas auditables — el encabezado RFC 8058 que lo hizo corto, y el techo honesto de entregabilidad.
■ space · notas de campo · fig 1
El boletín entero es 1.258 líneas: doble opt-in, baja en un clic, una CLI de envío — sin cuenta de plataforma.
La baja en un clic es un solo encabezado — RFC 8058, exigido por Google y Yahoo desde febrero de 2024.
Techo honesto: sin DKIM alineado, mail-tester ~5/10 y los receptores estrictos pueden mandarlo a spam — bien para una lista pequeña; un relay lo arregla.
Un boletín es tres endpoints, dos tablas, y un encabezado de email que la mayoría de las plataformas te esconde.
01¿POR QUÉ AUTOALOJAR TODO ESTO?
el inventario honesto — el intercambio en una pantalla; el archivo gana la propiedad, la plataforma gana el no-tener-que-pensar
| Este servidor | Plataforma alojada | |
|---|---|---|
| Líneas de código que puedo leer | las 1.258, todas | 0 |
| Propiedad de la lista | un archivo SQLite | botón de exportar |
| Darse de baja | encabezado RFC 8058, autofirmado | ajuste del panel |
| Techo de entregabilidad | ~5/10 mail-tester hasta alinear DKIM | su reputación |
| Tiempo hasta el primer envío | un fin de semana | una tarde |
rsync de desaparecer02LA RUTA DE SUSCRIPCIÓN
un POST, tres guardias — la firma es la única autoridad, así la puerta se abre con el libro dormido
RUTA 2 · CONFIRMAR — EL RELOJ LEE EL SELLO · LIBRO DORMIDO · VEREDICTO AÚN CONFIRMA
el tag lleva base64url(email|action) más un sello HMAC-SHA256 — sin sesión, sin tabla de tokens, nada que consultar
curl -X POST https://mrsaynothing.dev/letters/api/subscribe \
-H 'content-type: application/json' \
-d '{"email":"[email protected]"}'
subscribers, un CHECK que fija status en pending · confirmed · unsubscribed, y sends, el rastro de auditoríawebsite humans never see — a filled field buys a fake ok que los humanos nunca ven — un campo lleno compra un falso SET status='maybe' is refuseduna restricción CHECK tiene un solo trabajo — THE TOKEN PRESS
LA PRENSA DE TOKENS
import { createHmac, timingSafeEqual } from 'node:crypto';
// payload = base64url(email|action), MAC = HMAC-SHA256(payload)
export function sign(email: string, action: 'confirm' | 'unsub'): string {
const payload = Buffer.from(`${email}|${action}`).toString('base64url');
const mac = createHmac('sha256', config.hmacSecret).update(payload).digest('base64url');
return `${payload}.${mac}`;
}
timingSafeEqual contra un MAC recalculado — sin tabla de tokens, sin caducidad que gestionarUn enlace de confirmación que sigue funcionando cuando la base de datos duerme es una cosa menos que puede podrirse.
04LO QUE SE ROMPIÓ, LO QUE NO HARÁ
tres fallos, arreglados — y el techo, impreso por la propia instalación
pnpm install --frozen-lockfile corrió limpio en local y murió en el contenedor — el script postinstall de esbuild nunca fue aprobado. La solución: meter el pequeño pnpm-workspace.yaml declarando los scripts de build permitidos dentro de la imagen. Media jornada para encontrarlo, un archivo para arreglarlo.# the --dry flag renders the full text and HTML for review before anything moves
cli.mjs send --subject ... --file post.md
fin del boletín de un archivo · nada fetchado · todo local