MailPilot Agent
Crash-safe mail merge for AI agents.
MailPilot Agent helps AI coding agents preview, send, resume, and reconcile personalized email batches from CSV/XLSX.
It is designed for careful workflows like pre-sales follow-ups, event notifications, customer updates, and local-first automation.
Most email scripts just send. MailPilot previews first, skips unsafe rows, checkpoints every SMTP result, and resumes safely after interruption.
Features
- Reads Excel/CSV and auto-detects email, name, group, and sent-status columns.
- Simple and grouped modes: send one template to everyone, or choose templates per row with a
groupcolumn. - Preview before sending: see per-group counts, rendered samples, and unsafe rows before any email goes out.
- Crash-safe resume: writes an append-only JSONL checkpoint after every SMTP result.
- Safe testing: use
--dry-run,--redirect-to, and--limitbefore real sending. - Schedule and throttle: send later with
--at, or slow down batches with--sleep. - Bounce reconciliation: scan bounce notifications through IMAP and mark undelivered rows.
- Local-first: no SaaS account, no telemetry, no database required.
Safety Demo
Try the messy sample:
python scripts/mailer.py preview samples/messy_registrations.csv --out sendable.csv
The sample contains valid rows, empty emails, malformed emails, a missing template, and an already-sent row.
MailPilot Agent will show:
Read 5 row(s) -> wrote sendable.csv
Will send (grouped by template, 1 total):
[confirmed] 1 email(s)
Marked as already sent, will skip: 1 row(s)
Cannot send, needs your attention: 3 row(s) (will NOT be sent)
- (no email): no valid email address
- (no email): no valid email address
- [email protected]: template not found: templates/vip.txt
Nothing is sent during preview.
Quickstart
Install dependencies for direct folder usage:
pip install pandas openpyxl jinja2 pyyaml certifi
Copy and edit the config:
cp config.example.yaml config.yaml
python scripts/mailer.py doctor --config config.yaml
Preview a grouped list:
python scripts/mailer.py preview samples/event_registrations.csv --out sendable.csv
Preview a simple one-template list:
python scripts/mailer.py preview samples/attendees.csv --template default --out sendable.csv
Test before sending:
python scripts/mailer.py send --input sendable.csv --config config.yaml --redirect-to [email protected] --limit 3
Send for real:
python scripts/mailer.py send --input sendable.csv --config config.yaml
Reconcile bounces:
python scripts/mailer.py bounces --input sendable.csv --config config.yaml --apply
Installable CLI
You can also install it as a local CLI:
python -m pip install -e .
Then use:
mailpilot preview samples/event_registrations.csv --out sendable.csv
mailpilot send --input sendable.csv --config config.yaml --dry-run
Both commands are available:
mailpilot
mailpilot-agent
How It Works
MailPilot uses a review-first workflow:
CSV/XLSX -> preview -> confirm -> send -> checkpoint ledger -> bounce reconciliation
During sending, it sends one email at a time and appends the result to a JSONL ledger:
sendable.csv.sendlog.jsonl
If the process stops halfway through, run the same command again. MailPilot replays the ledger first and skips rows already accepted by SMTP.
The CSV is still updated for convenience, but it is written atomically instead of being rewritten after every single email.
List Format
| column | required | notes |
|---|---|---|
email |
yes | headers containing email / 邮箱 are auto-detected |
name |
optional | used for {{ name }} in templates |
group |
optional | enables grouped mode; value should match a template name |
sent |
optional | truthy rows such as yes, 1, 是, 已发送 are skipped |
Chinese headers are supported for common fields such as email, name, group, and sent status.
Templates
Templates are plain text files with Jinja2 variables.
Example:
Subject: You're confirmed
Hi {{ name }},
Your spot is confirmed.
Templates live in:
templates/
Examples:
templates/default.txt
templates/confirmed.txt
templates/waitlist.txt
In grouped mode, a row with group=confirmed uses:
templates/confirmed.txt
Common Commands
Preview:
python scripts/mailer.py preview list.csv --out sendable.csv
Dry run:
python scripts/mailer.py send --input sendable.csv --config config.yaml --dry-run
Redirect all emails to yourself for testing:
python scripts/mailer.py send --input sendable.csv --config config.yaml --redirect-to [email protected] --limit 3
Send only one group:
python scripts/mailer.py send --input sendable.csv --config config.yaml --only confirmed
Throttle sending:
python scripts/mailer.py send --input sendable.csv --config config.yaml --sleep 2
Schedule sending:
python scripts/mailer.py send --input sendable.csv --config config.yaml --at "2026-07-02 09:00"
Configuration
Copy:
cp config.example.yaml config.yaml
Fill in SMTP settings:
smtp:
host: smtp.gmail.com
port: 465
use_ssl: true
user: [email protected]
password: YOUR_APP_PASSWORD_HERE
from_addr: [email protected]
from_name: Your Name
unsubscribe: [email protected]
Use an app password, not your normal email password. See:
references/email_provider_setup.md
Deliverability Notes
send marking a row as sent means the SMTP server accepted it. It does not guarantee inbox placement.
For larger or recurring batches, use a transactional provider such as Amazon SES, SendGrid, Mailgun, or Aliyun DirectMail with SPF/DKIM/DMARC configured.
MailPilot is designed for responsible workflows:
- send only to recipients who expect the message
- preview before sending
- throttle larger batches
- keep unsubscribed or bounced addresses out of future lists
- include a working unsubscribe contact
Project Structure
mailpilot-agent/
mailpilot/ # installable Python package
scripts/mailer.py # direct folder entrypoint
templates/ # editable templates
samples/ # example CSV files
tests/ # pytest tests
SKILL.md # agent skill instructions
config.example.yaml # SMTP config template
Development
Install dev dependencies:
python -m pip install -e ".[dev]"
Run checks:
python -m pytest
python -m ruff check .
Roadmap
- HTML email templates
- Attachments
- SQLite checkpoint ledger option
- SendGrid / SES / Mailgun adapters
- Better DSN bounce parsing
- Richer preview reports
License
MIT — see LICENSE.
No comments yet
Be the first to share your take.