Hey everyone!
I'm excited to share a recent project — Job Outreach Automation, a Python tool I built to solve a very real problem from my own job search: personalizing and sending job-application emails to a large list of recruiters, without it turning into either hours of manual repetitive work or a risky spam-triggering bulk blast.
This project pushed me to think beyond "just loop and send an email" — into rate limiting, idempotent design, and handling sensitive data safely in a public codebase.
🧩 Tech Stack
Language: Python 3 (standard library only — no external dependencies)
Email: smtplib, email.mime for SMTP sending with attachments
Data: CSV for contacts and send-log tracking
CLI: argparse for dry-run and limit flags
Auth: Gmail SMTP with App Password authentication
💡 Project Overview
The tool takes a CSV of contacts (name, email, title, company), personalizes an email template per recipient, attaches a resume, and sends it through Gmail's SMTP server — while staying safely under sending limits and never emailing the same person twice, even across multiple days of runs.
Core features:
➕ Personalized emails — dynamically fills in each recipient's name and company
📋 Resumable & idempotent — every send is logged to CSV, so re-running the script never double-emails anyone
⏱️ Rate-limited sending — configurable daily limit + randomized delay between sends
🧪 Dry-run mode — preview exactly what would be sent, before sending anything for real
📎 Auto-attachment — resume gets attached to every email automatically
⚙️ How It Works
python send_emails.py --dry-run --limit 5 # preview only, sends nothing
python send_emails.py --limit 2 # small real test
python send_emails.py # sends up to the daily limit
🔐 Handling Sensitive Data
Since this touches real credentials (a Gmail App Password) and real personal data (other people's names and emails), I split the repo into a public, safe-to-share layer and a private, gitignored layer:
config.example.py / contacts.example.csv — safe templates, committed to the repo
config.py / contacts.csv / sent_log.csv — the real, personal versions, excluded via .gitignore and never pushed
This felt like an important habit to build early — even a small personal script shouldn't leak credentials or other people's data just because it's "just a side project."
🎯 What I Learned
Designing for idempotency using a persistent log instead of in-memory state
Balancing automation vs. platform trust — every feature that makes a tool "more automated" also makes it look more bot-like to spam filters, so restraint is a design choice, not a limitation
Structuring a small CLI tool with dry-run as a first-class mode, not a bolted-on flag
This was a great reminder that the hardest part of automation tooling usually isn't the "happy path" — it's the constraints around it: rate limits, safe resumption, and protecting sensitive data, even in a small personal-use script.
🔗 GitHub Repository
👉 View the source code: https://github.com/tejasviurka/Job-Outreach-Automation
Top comments (0)