Shlok Patel
← All projects
Production2025 – present

MailSender

Multi-source lead engine that scrapes, dedupes, and delivers 500+ qualified leads a day.

Role

Solo builder — architecture, scrapers, dashboard, ops

Stack

PythonPlaywrightGoogle Sheets APIGmail OAuthTelegram Bot APIReactGitHub Actions

Overview

Liffio's outbound engine needed a single system that could pull leads from Instagram, LinkedIn, Reddit, and Gmail, dedupe them across sources, sync into Google Sheets for the sales team, and page the founder on Telegram when interesting things happened — all without babysitting.

The problem

  • Sales was manually copy-pasting leads out of 4 different tools every morning.
  • No dedupe — the same prospect kept getting emailed twice from different lists.
  • Zero visibility into which source was actually producing meetings.
  • The scrapers that existed broke every time a platform shifted their DOM.

Approach

  • Modelled every source as a pluggable 'scraper' with a common lead schema so the dedupe layer downstream didn't care where a lead came from.
  • Chose Playwright over raw HTTP because Instagram and LinkedIn actively fingerprint and rotate; a real browser context was the only thing that survived a week.
  • Made Google Sheets the source of truth for the sales team — familiar UI, no extra tool to log into.
  • Wrapped the whole pipeline in GitHub Actions cron so there was no server to keep alive.

What I built

Four platform scrapers

Instagram, LinkedIn, Reddit, and Gmail. Each returns leads in the same normalized shape (name, handle, source, first_seen_at, context).

Dedupe + enrichment layer

Fuzzy-matches leads across sources on handle + display name, keeps the earliest seen record, merges context. Cuts ~30% duplicate outreach.

Sheets sync

Writes leads into a Google Sheet with source tags and status columns the sales team can filter on. Two-way sync so status changes flow back.

Telegram daily digest

Every morning: total new leads, top-3 hottest by score, per-source breakdown, and any scraper errors that need attention.

React operator dashboard

Small internal UI to trigger runs on demand, tail logs, and re-authenticate Gmail/Google when tokens expire.

Outcomes

  • Runs unattended 24/7 via GitHub Actions — zero infra bill.
  • Cut manual lead-gathering time from ~90 minutes/day to zero.
  • Dedupe layer alone removed roughly a third of duplicate outreach.
  • Telegram digest turned 'is the pipeline healthy?' from a 20-minute check into a 5-second read.

What I learned

  • Normalizing at the scraper boundary — instead of the dedupe layer — was the single biggest architectural win. Adding a fifth source now takes an afternoon.
  • Playwright + persistent browser contexts is dramatically more stable than rotating headers on raw HTTP for scraping targets that actively defend.
  • GitHub Actions cron is under-appreciated as a 'no-server' scheduler for personal scale automations.