Email an Excel / CSV report as an attachment with one command — and put it on a schedule with cron so the right people get the right spreadsheet every morning without you lifting a finger.
python -m excel_report_mailer --config mail.ini --attach sales.csv --to-xlsx --dry-runWould send: Daily sales report
From: reports@example.com
To: alice@example.com, bob@example.com
Attachment: sales.xlsx (4,983 bytes)
(dry run — nothing was sent)
📚 Built to go with the step-by-step guides at python-excel-automation.com — practical Python + Excel tutorials covering pandas, openpyxl, reporting and scheduling.
- 📎 Attaches your report — any
.xlsx/.csvfile, with the recipient list, subject, and body read from a small config file. - 🔄 CSV → XLSX on the fly — pass
--to-xlsxto convert a CSV into a proper Excel workbook (pandas + openpyxl) before sending. - 🔐 Keeps secrets out of the repo — the SMTP password is read from an environment variable, never stored in the config file.
- 👀
--dry-run— build and preview the exact email without connecting to a server. - ⏰ Cron-friendly — one command, so scheduling it is a one-line crontab entry.
Runs straight from a clone of the repository — there's nothing to install from a package index.
git clone https://github.com/python-excel-automation/excel-report-mailer.git
cd excel-report-mailerIt needs Python 3.9+ and two libraries — pandas and openpyxl (listed in
requirements.txt). Make them available in your Python environment using whatever package
manager you use, then run the tool from the repo folder.
Copy the example config and fill in your details:
cp examples/mail.example.ini mail.ini[smtp]
host = smtp.example.com
port = 587
use_tls = true
username = reports@example.com
password_env = SMTP_PASSWORD ; the env var to read the password from
[message]
from = reports@example.com
to = alice@example.com, bob@example.com
subject = Daily sales report
body = Hi team, attached is today's sales report.
attachment_name = sales-report.xlsxPut the password in the environment (never in the file):
export SMTP_PASSWORD='your-app-password'# Preview without sending
python -m excel_report_mailer --config mail.ini --attach report.xlsx --dry-run
# Send for real
python -m excel_report_mailer --config mail.ini --attach report.xlsx
# Convert a CSV to .xlsx, then send
python -m excel_report_mailer --config mail.ini --attach sales.csv --to-xlsx| Flag | Description |
|---|---|
-c, --config |
Path to the INI config file (required). |
-a, --attach |
Path to the file to attach (required). |
--to-xlsx |
If the attachment is a CSV, convert it to .xlsx first. |
--name |
Override the attached file's name. |
--dry-run |
Build and preview the email without sending. |
Send the report every weekday at 7am:
0 7 * * 1-5 cd /path/to/excel-report-mailer && SMTP_PASSWORD='…' python -m excel_report_mailer --config mail.ini --attach /data/daily.csv --to-xlsx >> mailer.log 2>&1from excel_report_mailer import send_report
# Preview
msg = send_report("mail.ini", "sales.csv", to_xlsx=True, dry_run=True)
print(msg["Subject"])
# Send (reads the password from the configured env var)
send_report("mail.ini", "report.xlsx")python -m excel_report_mailer --config examples/mail.example.ini --attach examples/sales.csv --to-xlsx --dry-runWith the dependencies and pytest available, run the tests from the repo folder:
python -m pytestThe test suite uses a fake SMTP transport, so no real email is ever sent.