Alejandro Rioja.
AI Agents Growth

Cómo Automatizar tu Newsletter con un Agente de IA

Alejandro Rioja
Alejandro Rioja
5 min de lectura
TL;DR

Un agente de Claude lee mi cola de contenido, elige el ángulo más fuerte de la semana, redacta un newsletter con mi voz, segmenta la lista por nivel de engagement y programa el envío a través de la API de Kit — todo sin que yo abra un editor. Reviso una vista previa renderizada y presiono aprobar. El trabajo creativo difícil es mío; la ejecución mecánica es del agente.

Newsletter gratuita

Cada miércoles. 28.400+ operadores. Sin relleno.

Tabla de contenidos

Actualizado junio 2026.

TL;DR: Un agente de Claude lee mi cola de contenido, elige el ángulo más fuerte de la semana, redacta un newsletter con mi voz, segmenta la lista por nivel de engagement y programa el envío a través de la API de Kit — todo sin que yo abra un editor. Reviso una vista previa renderizada y presiono aprobar. El trabajo creativo difícil es mío; la ejecución mecánica es del agente.

[Lectura del operador] Un newsletter que se envía de forma consistente supera a uno que es “mejor” pero que se publica cuando llega la inspiración. La restricción era la sobrecarga de ejecución, no las ideas. Tenía ideas; no tenía el ancho de banda para formatear, programar y segmentarlas cada semana. El agente eliminó esa brecha.

El verdadero cuello de botella en la mayoría de los flujos de newsletter

La mayoría de los consejos de automatización de newsletters se enfocan en lo incorrecto: secuencias de bienvenida, automatizaciones, lógica de etiquetado. Están bien, pero no resuelven el problema de creación semana a semana.

El verdadero freno es este: sabes lo que quieres decir, pero sentarte a formatearlo, escribir las variantes del asunto, elegir el segmento correcto y programarlo en el momento adecuado cuesta 2-3 horas de cambio de contexto por semana. Multiplícalo por 52 semanas y habrás pasado una semana laboral completa simplemente enviando newsletters.

El agente maneja cada paso después de “sé cuál es el ángulo de esta semana.”

El stack que estoy usando

Si no estás en Kit, el mismo patrón funciona con cualquier plataforma que tenga una API REST para crear y programar transmisiones.

Paso 1: La cola de contenido

El agente necesita una fuente de verdad sobre “de qué estamos escribiendo.” La mía es una tabla de Airtable con columnas:

Cada semana, paso 10 minutos añadiendo 2-3 temas a la cola. Esa es mi aportación creativa. El resto es el trabajo del agente.

Paso 2: El agente de borrador

typescript
// workers/newsletter-agent/index.ts
import Anthropic from "@anthropic-ai/sdk";
import Airtable from "airtable";

const client = new Anthropic();

const VOICE_SYSTEM = `You are writing a weekly newsletter for Alejandro Rioja's subscribers.
His audience: founders and operators interested in AI agents, SEO, and growing a one-person business.
Voice: direct, first-person, practitioner. No hype, no "exciting times," no excessive bullet lists.
Structure every newsletter as:
1. One-sentence hook (the problem or observation)
2. The core insight (3–5 paragraphs, no headers, conversational)
3. One concrete action the reader can take this week
4. A short sign-off (2 sentences max)
Subject line: specific, outcome-oriented, under 50 chars. No clickbait.
Return JSON: { "subject": "...", "preheader": "...", "body": "..." }`;

async function getNextTopic(): Promise<{ id: string; topic: string; notes: string; tier: string }> {
  const base = new Airtable({ apiKey: process.env.AIRTABLE_API_KEY }).base(process.env.AIRTABLE_BASE_ID!);
  const records = await base("Newsletter Queue")
    .select({ filterByFormula: "{Status} = 'Queue'", sort: [{ field: "Created", direction: "asc" }], maxRecords: 1 })
    .firstPage();
  if (!records.length) throw new Error("Queue is empty. Add topics.");
  const r = records[0];
  return { id: r.id, topic: r.get("Topic") as string, notes: (r.get("Notes") as string) ?? "", tier: (r.get("Tier") as string) ?? "all" };
}

async function draftNewsletter(topic: string, notes: string): Promise<{ subject: string; preheader: string; body: string }> {
  const msg = await client.messages.create({
    model: "claude-sonnet-4-6",
    max_tokens: 2048,
    system: VOICE_SYSTEM,
    messages: [{ role: "user", content: `Write this week's newsletter on: "${topic}". Additional notes: ${notes || "none"}` }],
  });
  const text = (msg.content[0] as any).text.replace(/```json\n?/, "").replace(/```/, "").trim();
  return JSON.parse(text);
}

async function scheduleWithKit(draft: { subject: string; preheader: string; body: string }, tier: string): Promise<string> {
  const segmentId = tier === "engaged" ? process.env.KIT_ENGAGED_SEGMENT_ID : null;
  const sendAt = new Date();
  sendAt.setDate(sendAt.getDate() + ((4 - sendAt.getDay() + 7) % 7)); // next Thursday
  sendAt.setHours(9, 0, 0, 0); // 9am CT

  const payload: any = {
    broadcast: {
      subject: draft.subject,
      content: draft.body,
      description: draft.preheader,
      send_at: sendAt.toISOString(),
      email_layout_template: "minimal",
    },
  };
  if (segmentId) payload.broadcast.segment_id = segmentId;

  const res = await fetch("https://api.kit.com/v4/broadcasts", {
    method: "POST",
    headers: { "Content-Type": "application/json", "X-Kit-Api-Key": process.env.KIT_API_KEY! },
    body: JSON.stringify(payload),
  });
  const data = await res.json();
  return data.broadcast?.id ?? "";
}

export default {
  async scheduled(_event: ScheduledEvent, env: Env) {
    // Inject env vars
    Object.assign(process.env, env);
    const { id, topic, notes, tier } = await getNextTopic();
    const draft = await draftNewsletter(topic, notes);
    const broadcastId = await scheduleWithKit(draft, tier);

    // Mark as Approved in Airtable (not Sent — human reviews the Kit preview before confirm)
    const base = new Airtable({ apiKey: env.AIRTABLE_API_KEY }).base(env.AIRTABLE_BASE_ID);
    await base("Newsletter Queue").update(id, { Status: "Approved", KitBroadcastId: broadcastId });

    console.log(`Scheduled broadcast ${broadcastId} for topic: ${topic}`);
  },
};

Paso 3: El paso de aprobación

El agente crea la transmisión en estado de borrador de Kit y marca el registro de Airtable como “Approved.” Kit me envía una notificación con un enlace de vista previa. Hago clic, lo leo y, si se ve bien, confirmo el envío. Si quiero cambios, edito directamente en Kit.

Esta es la puerta que evita que el agente sea completamente autónomo en el correo saliente. Confío en los borradores aproximadamente el 90% de las veces. El 10% que detecto en la revisión — un tono ligeramente incorrecto, una estadística que quiero verificar, un enlace que quiero añadir — vale los 3 minutos de revisión.

Lo que el agente maneja que nunca más quiero hacer

Lo que sigo siendo mío

La idea. El tema en la cola es mío. El ángulo es mío. El agente es un gran ejecutor de un brief claro; no es una capa de estrategia. Si pongo un tema malo en la cola, obtengo un newsletter bien escrito sobre un tema malo.

También: la puerta de primera revisión. Cada envío pasa por mis ojos antes de salir. Eso no va a cambiar.

La conclusión del operador

Si estás pasando más de una hora a la semana en mecánicas de newsletter — formateo, programación, segmentación — deberías automatizarlo. La API de Kit es limpia, el disparador cron del Worker es sólido como una roca, y la calidad del borrador de Claude es suficientemente alta como para que apruebe ~90% de los primeros borradores sin cambios. Construye la cola en Airtable, conecta el Worker y vuelve a crear ideas en lugar de ejecutar envíos.

Seguir leyendo

Recibe el manual de IA en tu buzón

Cada miércoles. 28.400+ operadores. Sin relleno.

↵ para ver todos los resultados esc esc para cerrar