02 — Technical case study
Lead-gen
engine.
Pipeline ETL en 8 fases que convierte una región geográfica en una secuencia de cold emails B2B hipersegmentados — con previews HTML personalizados generados por IA y compliance LSSI-CE de serie.
- Role
- Solo engineer
- Year
- 2026
- Status
- Live · production
- Scope
- Pipeline · CLI · Compliance
- Stack
- Python · Playwright · Claude
- Sector
- Sales · Outreach · NDA
01
Pipeline.
Numbered stages · CSV between
Cada fase es un script independiente con un único contrato — lee CSV, escribe CSV. Re-ejecutables, atómicas, debuggables paso a paso.
- 01
Scrape Maps
Iteración sobre N localidades × M categorías vía
Google Places API (New). Emitedata/leads_raw.csvcon place_id, web declarada, geo y metadata. Idempotente — re-ejecutable sin duplicar. - 02
Qualify
Filtra leads que no cumplen criterios de "web pobre": ausencia de sitio, no-https, redirección a redes sociales (
linktr.ee, instagram, facebook),PageSpeed mobile < 50, o load > 5s. Razón de descarte registrada en cada fila. - 02.5
Enrich emails (cascade)
Búsqueda en cascada hasta encontrar email: (1) scraping de la web propia → (2) Google Custom Search snippets → (3) bio Instagram → (4) "About" Facebook. Marca
enrichment_statuscon la fuente exacta onot_found. - 03
Generate previews
Claude genera HTML personalizado por lead — hero, secciones, CTA — con brief de estilo determinista.
Playwrightabre Chromium headless en viewport 1440×2000 y captura PNG. Archivos quedan enpreviews/<place_id>/. - 04
Send
Envío vía Gmail SMTP con app password. Preview embebido
inline cid:para máximo impacto visual. Throttle75s ± 25%entre envíos, max50/run, blacklist y log de envíos endata/sent_log.csvpara idempotencia. - 05+
Multi-channel queue
Para leads sin email descubierto, scripts secundarios alimentan colas alternativas:
05_whatsapp_queue.py+06_open_whatsapp.pyabren WhatsApp Web pre-rellenado,07_manual_queue.pyexporta CSV para gestión manual.
02
Flow.
CSV-driven · idempotent
// pipeline · stage flow
config.yaml
│
▼
┌──────────────┐ leads_raw.csv
│ 01 scrape │ ─────────────────▶ Places API
└──────┬───────┘
▼
┌──────────────┐ leads_qualified.csv
│ 02 qualify │ ─────────────────▶ PageSpeed API
└──────┬───────┘ (filter: pobre web)
▼
┌──────────────┐ + email column
│ 02.5 enrich │ ─────────────────▶ web · CSE · IG · FB
└──────┬───────┘ (cascade fallback)
▼
┌──────────────┐ previews/<id>/index.html
│ 03 previews │ ─────────────────▶ Claude API
└──────┬───────┘ Playwright PNG
▼
┌──────────────┐ sent_log.csv
│ 04 send │ ─────────────────▶ Gmail SMTP
└──────────────┘ inline preview · throttle 03
Legal.
Compliance baked-in
Cold email B2B serio — no growth-hack. Cumplimiento LSSI-CE codificado a nivel de pipeline, no de buena voluntad.
- Marco legal
- LSSI-CE art. 21 — España / UE
- Audiencia
- Solo personas jurídicas (B2B). Emails personales descartados
- Identificación
- Remitente, NIF y dirección física en cada email
- Opt-out
- Link de baja funcional · respuesta automática añade a blacklist
- Throttle
- 75 s ± 25% entre envíos · 50 emails/run · warm-up progresivo
- Idempotencia
- sent_log.csv evita re-envíos · place_id como clave única
04
Integrations.
8 external APIs orchestrated
- Lead source
- Google Places API (New) — búsquedas geo-segmentadas con radio configurable
- Quality signal
- Google PageSpeed Insights API — score mobile, LCP, blocking time
- Email enrichment
- Cascada — web scraping + Google CSE + Instagram bio + Facebook About
- Content generation
- Anthropic Claude (sonnet) con prompt de estilo determinista
- Visual capture
- Playwright Chromium headless · viewport 1440×2000 · screenshot PNG
- Color sampling
- ColorThief + Pillow para extraer paleta visual del logo/web del lead
- Email rendering
- Jinja2 templates · Premailer para inline-CSS · cid: para imágenes embebidas
- Delivery
- Gmail SMTP con app password · BCC opcional · dry-run mode
05
Stack.
Production dependencies
Core
- Python 3.10+
- pandas
- PyYAML
- python-dotenv
- Jinja2
- requests
AI · Visual
- anthropic 0.39+
- Playwright 1.45+ (Chromium)
- Pillow
- ColorThief
- Premailer
Web
- Flask 3.0 (preview server)
- tldextract
Pipeline
- 8 numbered stages
- Idempotent re-runs
- Single-lead shortcut
- Dry-run mode