A highly intelligent, autonomous, and LLM-agnostic cold email orchestration engine.
Designed specifically for engineers, founders, and recruiters who need to scale hyper-personalized outreach. Auto Mailer fuses your local resume data with live web-scraped company context to generate, gate, and deliver bespoke emails without triggering spam filters.
The diagram below illustrates how target company details are dynamically matched with your portfolio context, and then validated through quality gates:
graph TD
A[CSV Input: Company, Name, Email] --> B[load_companies]
B --> C{Tag available in CSV?}
C -- No --> D[infer_company_tag]
D --> E[Scraped Homepage/Context Text]
E -->|Keyword Token Intersection| F[Resolve Best Tag: Fintech, Security, Audio, ML, etc.]
C -- Yes --> G[Use CSV Tag]
F --> H[build_candidate_context]
G --> H
H -->|Selects relevant projects from DOMAIN_PROJECT_MAP| I[Injects CLASP / Regavis / RAGS descriptions]
I --> J[Multi-Key LLM Engine: Failover & Rotation]
J --> K[Format validation: 4 Paragraphs, Dynamic Subject]
K --> L[Programmatic python sign-off append]
L --> M[calculate_quality_score Gate]
| Component | Legacy Code (v1.0) | Upgraded Code (v2.0) | Rationale |
|---|---|---|---|
| Multi-Key Failover | Single API Key (Hard crash on 429) | Multi-Key Pool (LLM_API_KEY=k1,k2,k3) with automatic quarantine |
100% uninterrupted generation across provider rate limits |
| Token Budget | GEN_MAX_TOKENS = 420 |
GEN_MAX_TOKENS = 1500 |
Fixes mid-generation truncation crash |
| Subject Lines | Hardcoded static / generic strings | Curated human-written Systems & ML preset subjects | High open rates, zero hackathon spam triggers |
| Outreach Tone | Generic buzzwords, brief call asks | Vision appreciation, deep technical pitch, direct ask | Authentic, human-written tone; no forced demo requests |
| CSV Columns | Company, Email, Tag, Region, Note |
Company, Name, Email |
Simplifies pipeline setup |
| Project Routing | Direct CSV tag mapping | Dynamic keyword-based context matching | Preserves project targeting without manual tags |
| Quality Gate | 100 points: word count & CSV Tag/Note checks | 100 points: name, context match, length sanity | Fits 220-350 word format without false penalties |
| Contact Score | 10-point scale: Tag/Note/Region weight | 5-point scale: Email validity, corporate domain, sent history | Removes dead weight columns |
| Fallback Template | Legacy 4-bullet layout with old details | Modern 4-paragraph layout with CLASP & Regavis | Matches standard generation format |
| Checkpoint Sender | Index-based lookup ("1", "2") |
Email-based lookup (with fallback to index string) | Restores checkpoint safety and migration compatibility |
Clone the repository and install the dependencies:
git clone https://github.com/zibranxo/auto-mailer.git
cd auto-mailer
pip install -r requirements.txtCreate a .env file in the root directory. Auto Mailer v2 has moved all tunable parameters to environment variables for maximum flexibility.
# ── LLM Provider Configuration ──────────────────────────────────────────
# Multi-Key Pool for Zero-Interruption Failover:
# Option A (Comma-separated keys for same provider):
LLM_API_KEY=nvapi-key-1,nvapi-key-2,nvapi-key-3
# Option B (Numbered environment variables):
# LLM_API_KEY=nvapi-key-1
# LLM_2_API_KEY=nvapi-key-2
# LLM_3_API_KEY=nvapi-key-3
LLM_BASE_URL=https://integrate.api.nvidia.com/v1
LLM_MODEL=meta/llama-3.3-70b-instruct
LLM_FALLBACK_MODEL=deepseek-ai/deepseek-v4-flash
LLM_QUARANTINE_S=600
# ── Sender Configuration (Supports up to 10 accounts for rotation) ──────
SENDER_NAME="Arnav Sagar"
SENDER_EMAIL=primary_account@gmail.com
SENDER_APP_PASSWORD=your_primary_app_password
# Optional secondary accounts (auto-balanced and rotated)
SENDER_2_EMAIL=secondary_account@gmail.com
SENDER_2_APP_PASSWORD=your_secondary_app_password
SENDER_3_EMAIL=third_account@gmail.com
SENDER_3_APP_PASSWORD=your_third_app_password
# ── Limits & Quality Gates ──────────────────────────────────────────────
RATE_LIMIT_SECONDS=4
GEN_MAX_TOKENS=1500
EMAIL_MAX_WORDS=400
EMAIL_MAX_SUBJECT_LEN=100
MIN_CONTACT_SCORE=2
MIN_QUALITY_SCORE=70
VARIANT_COUNT=1Note: If using Gmail, you must use an App Password with 2FA enabled.
Ensure the following files are populated in the root directory:
hr_emails_directory.csv: ColumnsCompany,Name,Email.about_me.md: Your detailed candidate profile/pitch.resume.pdf: The attachment to send.
Never get blocked by LLM rate limits or billing interruptions again:
- Multi-Key Pool: Provide multiple API keys for the same provider via
LLM_API_KEY=key1,key2,key3or numbered variables (LLM_API_KEY,LLM_2_API_KEY,LLM_3_API_KEY). - In-Flight 429 Failover: When a key hits
429 Too Many Requests, it is quarantined forLLM_QUARANTINE_S(10 minutes) and generation immediately fails over to the next key without failing the draft. - Auth & Quota Protection: If a key hits
401 Unauthorizedor quota exhaustion, it is automatically disabled for the run and generation continues with the remaining keys.
Emails are crafted to sound like an authentic, highly capable engineering student reaching out directly to a team:
- Company Appreciation: Opens with genuine appreciation for what the company is building and its vision.
- Candidate Background & Fit: Highlights Arnav Sagar (DTU Software Engineering, CGPA 8.75) and strong Data Structures & Algorithms (DSA) problem-solving skills in C++ and Python.
- Engineering Depth: Deep dives into 2 key matching projects with concrete technical metrics (e.g. CLASP distributed proxy with token-bucket rate limiting across 18 APIs; Regavis audio deepfake cascade cutting compute ~85%; AIMS-DTU sub-10ms moderation pipeline).
- Direct & Humble Ask: Confirms resume is attached and directly asks for internship consideration—zero pressure for brief calls, 10-minute chats, or live demos.
- Zero Hackathon Cliches: Purged of generic hackathon/contest bragging in both subject lines and email copy.
Isolate different outreach campaigns cleanly. Instead of mixing targets and checkpoints, you can isolate all inputs and output run reports into a specific campaign directory:
python mailer.py --folder campaigns/summer_2026 --dry-run- Behavior:
- Auto Mailer searches for the CSV database at
campaigns/summer_2026/hr_emails_directory.csv(falls back to any.csvin that folder if the default name is missing). - Saves run reports, checkpoints, logs, and cache indexes inside
campaigns/summer_2026/runs/andcampaigns/summer_2026/.
- Auto Mailer searches for the CSV database at
Generate and preview emails locally using the Rich terminal interface without sending actual emails:
python mailer.py --dry-run --company-research --limit 5- Key Benefit: Allows you to verify LLM response formatting, dynamic subject headers, and personalization tokens before dispatching them.
Visits the target company's domain, scraping <title> and <meta> description headers to inject real-world context into the LLM prompt.
python mailer.py --company-research --limit 10- Dynamic Routing: If a company does not have a hardcoded
Tagparameter, the scraped context is sent toinfer_company_tag()which uses keyword token intersection to match it to a domain (Fintech,Security,Audio,Vision/Aerospace,5G/Telecom,AI/ML). This dynamically selects the best projects from your portfolio to pitch.
Generate multiple email drafts in parallel, grade them against quality scoring gates, and choose only the highest-scoring candidate to deliver:
python mailer.py --company-research --variant-count 3 --limit 5- Usage: Setting
--variant-count 3generates 3 independent emails with slightly different temperatures and selects the most relevant, natural-sounding copy.
If the script gets interrupted by a network timeout or system shutdown, you can safely resume exactly where you left off without duplicating emails.
You can run it as a standalone flag without arguments to automatically resume the latest run:
python mailer.py --resume- Behavior: Loads the last processed index from the run checkpoint and continues the sequence.
- Date Rollovers: If you are resuming a run on a new calendar day (since runs are grouped in directories named by date, e.g.,
YYYY-MM-DD), executing--resumewithout a path will target today's folder. To target a previous day's run, pass the path directly:python mailer.py --resume campaigns/summer_2026/runs/2026-07-11
Connects to your Gmail/SMTP inbox via IMAP to scan for delivery failure notifications and adds those emails to bounced_log.json to automatically suppress future attempts:
python mailer.py --check-bounces --company-researchQueries DNS MX records before generating an email to ensure the domain actually has a working mail server:
python mailer.py --check-mx --limit 50- Benefit: Skips invalid domains entirely to protect your domain sending reputation and completely avoid hard bounces.
Get instant and detailed feedback after a run is completed. Auto Mailer prints a highly styled Rich table summarizing:
- Total database target targets loaded.
- Successful vs. failed SMTP sends.
- Skipped counts categorized by reason (duplicates, already sent, low score, invalid format).
- LLM draft generation successes and failures.
If any errors occurred (e.g. an LLM API error or SMTP failure), it prints a secondary table highlighting the exact company name, email address, stage where it failed, and the error code/message.
At the end of a run, the system also saves two reports under your campaign's run directory:
run_report_YYYYMMDD_HHMMSS.json: A structured database format for programmatic integration.run_report_YYYYMMDD_HHMMSS.md: A beautiful markdown summary document.
Scale beyond Gmail's rolling 500 emails/day restriction by load-balancing outreach across multiple accounts:
- Round-Robin Rotation: The script automatically rotates through all defined sender accounts (up to 10) in your
.envfile to balance the load evenly. - Auto-Retirement on Block: If a sender account hits Google's sending limit (
550 Daily user sending limit exceeded) or has authentication issues, the script will automatically retire it from the active rotation pool and output a terminal warning. - Seamless Retry: The email sending attempt will immediately rotate to the next active sender and retry the delivery—the draft is never skipped or failed due to a blocked sender account.
Avoid hitting spam folders and maintain your sender account reputation:
- Randomized Jitter Pacing: Introduces dynamic randomized sleep variation (80% to 120% of your configured
RATE_LIMIT_SECONDS) between email dispatches to prevent bot-like patterns and mimic natural human behavior. - No Tracking Headers: Disables non-standard headers (like
X-Entity-Ref-ID) that corporate mail filters commonly flag as bulk cold outreach indicators. - Smart Charset Formatting: Configures MIME components (
MIMEText,Header) explicitly to UTF-8 to prevent character encoding degradation (e.g. garbled characters) on modern mail clients.
Auto Mailer v2 uses two main heuristic gates to evaluate target quality:
Evaluates whether a target recipient is valid. Controlled by MIN_CONTACT_SCORE (default: 2).
- Valid Email Format: +2 points
- Corporate Domain Indicator: +2 points (for domains ending in
.co,.org,.gov,.edu, etc.), +1 point for custom domains, +0 points for generic personal emails (gmail/yahoo). - Communication History: +1 point if not previously contacted, -1 point if contacted.
Evaluates whether the generated email is well-written. Controlled by MIN_QUALITY_SCORE (default: 70).
- Subject Length ≤ 100 characters: +5 points
- Body Length Sanity (50-500 words): +5 points
- Company Name Mentioned in Body: +20 points
- Scraped Context Keyword Matched: +15 points (at least one non-stopword token from the scraped web text appears in the generated body)
- Technical Personalization Keywords: +25 points (presence of keywords like
llm,rag,yolo,proxy,deepfake, etc.) - Professional Tone Check: +15 points (absence of stiff phrases like "please find attached my cv", "respected sir", etc.)
- Spam Likelihood Check: +15 points (absence of spam triggers like "100% guaranteed", "urgent", etc.)
| Argument | Description | Default |
|---|---|---|
--dry-run |
Generate and print emails to console without sending. | False |
--folder |
Encapsulate CSV inputs, logs, and checkpoints inside a folder. | None |
--company-research |
Enable active BeautifulSoup4 web scraping. |
False |
--variant-count |
Generate N variants concurrently. |
1 |
--check-bounces |
Parse IMAP inbox for hard bounces to suppress future attempts. | False |
--check-mx |
Query DNS for MX records before sending. | False |
--workers |
Number of concurrent threads for LLM API calls. | 1 |
--limit |
Maximum number of successful contacts to process. | All |
--resume |
Resume execution from the latest checkpoint in runs/. |
False |
auto-mailer/
├── mailer.py # 🧠 Core orchestration engine
├── test_mailer.py # 🧪 Full Unit testing suite
├── send_from_saveprogress.py # 📇 Offline/Cache direct sender
├── requirements.txt # 📦 Dependencies (OpenAI, Rich, BS4, etc.)
├── .env # 🔑 Global tunable configurations
├── hr_emails_directory.csv # 📇 Target directory (fallback)
├── about_me.md # 📝 Identity & Pitch grounding context
├── resume.pdf # 📄 Attachment file
└── campaigns/ # 📂 Isolated campaigns folders
└── summer_2026/ # 📂 Target campaign folder
├── hr_emails_directory.csv
├── sent_log.json
├── bounced_log.json
└── runs/ # 📂 Isolated campaign execution logs
Ensure compliance with CAN-SPAM, GDPR, or applicable local outreach regulations when utilizing automated email sequences.
Built with ❤️ for intelligent automation by Arnav Sagar.