MailForge loads a CSV of contacts and a Jinja2 template with {{name}} / {{company}} placeholders, then sends each contact a uniquely personalized email — logging every send with automatic retry on failure.
Most bulk-send scripts fire straight into your contacts' inboxes. MailForge makes proofing and pacing first-class citizens of the workflow, not an afterthought.
Run with --dry-run and MailForge renders every single personalized email as its own HTML file in a local /preview folder — one file per contact, fully rendered with their real name and company. Open the folder in a browser and read through all 47 versions before a single message leaves your SMTP server. Typos, broken merge fields, and awkward phrasing get caught while they're still free to fix.
Pass --rate 10/min and sends are throttled to a steady, human-plausible pace instead of blasting your entire list in one burst. Bursty sending is exactly what triggers spam filters and provider rate limits — pacing sends keeps your domain's reputation intact and your emails out of the junk folder.
No frameworks, no dashboard, no vendor lock-in — just a focused Python CLI built on the standard tools for the job.
Install dependencies
pandas and Jinja2, pinned in requirements.txt.
Configure SMTP credentials
Copy .env.example to .env and fill in your mail server.
Preview every email
--dry-run renders the full batch to /preview — nothing sends.
Send, paced
--rate 10/min throttles delivery and logs every result.