■ space · полевые записи · fig 1
Вся рассылка — это 1 258 строк: двойной opt-in, отписка в один клик, CLI отправки — без аккаунта платформы.
Отписка в один клик — это один заголовок — RFC 8058, обязательный для Google и Yahoo с февраля 2024 года.
Честный потолок: без выровненного DKIM, mail-tester ~5/10 и строгие получатели могут закинуть в спам — для небольшого списка нормально; релей это чинит.
Рассылка — это три эндпоинта, две таблицы и один email-заголовок, который большинство платформ от вас прячет.
01ВООБЩЕ ЗАЧЕМ САМОХОСТИНГ?
честная инвентаризация — весь размен на одном экране; файл выигрывает владение, платформа — не-надо-думать
| Этот сервер | Хостинговая платформа | |
|---|---|---|
| Строк кода, которые я могу читать | все 1 258 | 0 |
| Владение списком | один файл SQLite | кнопка экспорта |
| Отписка | заголовок RFC 8058, самоподписанный | настройка в дашборде |
| Потолок доставляемости | ~5/10 mail-tester, пока DKIM не выровнен | их репутация |
| Время до первой отправки | выходные | вечер |
rsync от исчезновения02ПУТЬ ПОДПИСКИ
один POST, три охранника — подпись — единственная власть, так что дверь открывается при спящем реестре
МАРШРУТ 2 · ПОДТВЕРДИТЬ — ПРИБОР ЧИТАЕТ СКРЕПУ · РЕЕСТР СПИТ · ВЕРДИКТ ВСЁ ЕЩЁ ПОДТВЕРЖДАЕТ
тег несёт base64url(email|action) плюс скрепу HMAC-SHA256 — ни сессии, ни таблицы токенов, нечего и вычислять
curl -X POST https://mrsaynothing.dev/letters/api/subscribe \
-H 'content-type: application/json' \
-d '{"email":"[email protected]"}'
subscribers, CHECK прибивает status к pending · confirmed · unsubscribed, и sends, аудит-следwebsite humans never see — a filled field buys a fake ok, которого люди никогда не видят — заполненное поле покупает фальшивое SET status='maybe' is refusedCHECK-ограничение делает одну работу — THE TOKEN PRESS
ПРЕСС ДЛЯ ТОКЕНОВ
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 против пересчитанного MAC — ни таблицы токенов, ни срока годностиЛинк подтверждения, который работает, пока база спит, — одна вещь меньше, способная сгнить.
04ЧТО СЛОМАЛОСЬ, ЧЕГО ОН НЕ УМЕЕТ
три поломки, починены — и потолок, напечатанный самим setup-ом
pnpm install --frozen-lockfile работал чисто локально и умирал в контейнере — postinstall-скрипт esbuild так и не был одобрен. Фикс: вложить в образ маленький pnpm-workspace.yaml со списком разрешённых build-скриптов. Полдня на поиск, один файл на починку.# the --dry flag renders the full text and HTML for review before anything moves
cli.mjs send --subject ... --file post.md
конец рассылки в одном файле · ничего не fetched · всё локально