Evergreen Report Emailer
Email a spreadsheet report to the right people on a schedule, automatically, from a Windows PC.
Point it at an Excel or CSV file, or a folder where your exports land, and it sends a clean email with the data in a table, totals for the columns you choose, and the file attached. Set it to run every Monday at 8, on the 1st of the month, or whenever suits you.
- Nothing to install. It runs on PowerShell, which is built into Windows 10 and 11. Excel doesn't need to be installed either.
- Excel or CSV. Reads .xlsx and .csv files, including the CSV files Excel and most accounting, sales and CRM tools export.
- Always the latest file. Point it at a folder and it picks the newest matching file, for exports named like
sales-2026-10-12.csv. - A tidy email. Your message, a table of the data, totals, and the original file attached. Long reports show the first rows and attach the rest.
- Sends through Outlook or Gmail.
- Classic Outlook: sends from your own Outlook with no passwords to store. Best for Microsoft 365 offices.
- SMTP: Gmail, Google Workspace, Zoho and most other email services, using an app password that's stored encrypted for your Windows account only.
- Runs on a schedule. Daily, weekdays, weekly or monthly, through Windows Task Scheduler. If the PC was off at that time, the report goes out as soon as it's back on.
- Doesn't send bad reports. It can skip a report when the file is empty or hasn't been updated recently, and email you instead so you know the export didn't run.
- Preview first. See exactly what the email will look like in your browser before anything is sent.
Quick start (about 15 minutes)
- Unblock and unzip. Right-click the ZIP you downloaded, choose Properties, tick Unblock if it's shown, click OK, then right-click → Extract All. Put the folder somewhere short and permanent, like
C:\ReportEmailer. - Open the menu. Double-click Report Emailer.bat. Choose 1 to preview one of the two sample reports. It opens in your browser. Nothing is sent.
- Describe your report. Open Settings Builder.html in the same folder, fill in the form, and download
reports.jsoninto this folder, replacing the old one. (Or choose 6 to edit the file in Notepad;SETTINGS.mdexplains every option.) - Choose how to send. Follow
EMAIL-SETUP.md. With classic Outlook there's nothing else to do. For Gmail, create an app password and save it with menu option 5. - Send yourself a test. Put your own address in
"to", choose 2, and check your inbox. - Turn on the schedule. Choose 3. Each report with a
"schedule"will now run by itself.
What's in the folder
| File | What it is |
|---|---|
Report Emailer.bat | Double-click to open the menu |
reports.json | Your settings: which files, who gets them, when |
Settings Builder.html | A form that writes reports.json for you. Opens in your browser |
sample-data/ | Two sample reports to try. Delete when you're set up |
app/ | The program. You don't need to open these files |
logs/ | A record of every report sent or skipped (created on first send) |
previews/ | Previews from menu option 1 |
secrets/ | Your encrypted SMTP password, if you use SMTP |
Good to know
- The PC needs to be on and signed in at the scheduled time. Locked is fine. If it was off or asleep, Windows sends the report as soon as you're back.
- Moving the folder? Choose 3 again afterwards so the schedules point to the new place.
- Changed the settings? If you changed a schedule, choose 3 again. Other changes take effect on the next send.
- Run it from another program (for advanced users):
powershell -ExecutionPolicy Bypass -File app\Run-Report.ps1 -Report "Weekly sales". Add-Previewto preview only. Exit code 0 = sent, 2 = skipped, 1 = failed.
Troubleshooting
| What you see | Fix |
|---|---|
| Double-clicking the .bat flashes and closes, or Windows warns about the file | Unblock the ZIP before extracting (step 1). If Windows SmartScreen shows "Windows protected your PC", click More info → Run anyway. |
| "Classic Outlook for Windows was not found" | You're using the new Outlook app, which can't be automated by any program. Switch back to classic Outlook (see EMAIL-SETUP.md), or use SMTP. |
| Outlook asks "A program is trying to send an email" | Outlook shows this when it thinks your antivirus is out of date. Make sure Windows Security is on and up to date, or ask your IT person to allow programmatic access. |
| "The mail server refused the email" | Check the address and app password. Gmail needs an app password, not your normal password. |
| "Your Microsoft 365 account blocks password sending" | Use "method": "outlook". Microsoft is turning off password-based sending for Microsoft 365. |
| "Not sent: ... more than 24 hours ago" | The file hasn't been updated. Check the export that creates it ran. Change "max_age_hours" if your file is updated less often. |
| A column looks wrong, or totals are off | Use Preview. Notes at the top of the preview explain any column it couldn't find or values it couldn't add up. |
| A schedule didn't run | Check the log (option 7). Open Task Scheduler from the Start menu and look in the Evergreen Report Emailer folder for the task's last run result. |
Need help?
Email evergreen.code.info@gmail.com. See LICENSE.txt for your license terms.
Settings
All settings live in reports.json, next to Report Emailer.bat.
The easy way: open Settings Builder.html from the Report Emailer folder (or use it online at evergreencode.store/tools/report-emailer-settings/). Fill in the form, click Download reports.json, and save it into the folder, replacing the old one. It checks your settings as you go.
By hand: open reports.json from the menu (option 6) or in Notepad.
It's a JSON file, so keep the punctuation exactly as it is: text in "double quotes", a comma between items, and no comma after the last item in a list. If you make a mistake, the menu tells you roughly where. To check the result without sending anything, use Preview (option 1).
Folder paths use double backslashes in JSON: "C:\\Exports\\Sales". Forward slashes also work: "C:/Exports/Sales".
A complete example
{
"email": {
"method": "outlook",
"alert_to": "me@mybusiness.com"
},
"footer": "Sent automatically by Report Emailer.",
"accent_color": "#1d5c45",
"reports": [
{
"name": "Weekly sales",
"source": "C:\\Users\\Pat\\Downloads",
"pattern": "sales-export*.csv",
"to": ["owner@mybusiness.com", "sales@mybusiness.com"],
"subject": "Weekly sales - {date}",
"intro": "Hi team,{n}{n}Here are last week's sales.",
"totals": ["Amount"],
"max_age_hours": 24,
"schedule": { "every": "week", "days": ["Mon"], "time": "8:00 AM" }
}
]
}
Email settings
These go inside "email": { ... } and apply to every report. EMAIL-SETUP.md walks through each method.
| Setting | What it does | Example |
|---|---|---|
method | "outlook" (classic Outlook on this PC) or "smtp" | "outlook" |
outlook_account | Outlook only. Send from this account instead of your default one | "reports@mybusiness.com" |
from | SMTP only. The address emails come from | "me@gmail.com" |
from_name | SMTP only. The name people see | "Acme Reports" |
smtp_server, smtp_port | SMTP only. Your provider's server, port 587 | "smtp.gmail.com", 587 |
smtp_user | SMTP only. Login name, if different from from | "me@gmail.com" |
reply_to | SMTP only. Where replies go | "office@mybusiness.com" |
alert_to | Who gets a short email when a report is skipped or fails. Leave blank for none | "me@mybusiness.com" |
footer and accent_color (the table header color, as #rrggbb) sit outside "email" and apply to every report.
Report settings
Each report is one { ... } block in the "reports" list.
| Setting | What it does | Default |
|---|---|---|
name | Required. A short, unique name. It's also the name of the scheduled task | |
source | Required. A file ("C:\\Reports\\invoices.xlsx"), a folder ("C:\\Exports"), or a folder and pattern ("C:\\Exports\\sales*.csv"). Paths without a drive letter are relative to this folder | |
pattern | When source is a folder: which files to consider. The newest match is sent | "*" (any .csv or .xlsx) |
sheet | Excel only. Which sheet to read | the first sheet |
skip_rows | Skip this many rows before the header row, for exports with a title line at the top | 0 |
to, cc, bcc | Recipients: a list ["a@x.com", "b@x.com"] or one text "a@x.com; b@x.com" | to is required |
subject | Email subject. Can use the placeholders below | "{report} - {date}" |
intro | Your message above the table. {n} starts a new line, {n}{n} a new paragraph | "Hi,{n}{n}Here is the latest {report}." |
columns | Show only these columns, in this order. Names match the header row, ignoring capitals | all columns |
totals | Add up these columns and show the totals above the table | none |
max_rows | Rows shown in the email. The full file is attached. 0 shows every row | 50 |
show_table | false to send only the message, totals and attachment | true |
attach | false to not attach the file | true |
date_format | How Excel dates appear, for example "d/M/yyyy" or "yyyy-MM-dd" | "M/d/yyyy" |
skip_if_empty | Don't send if the file has no rows | true |
max_age_hours | Don't send if the file is older than this, which usually means the export didn't run. 0 turns this off | 0 |
schedule | When to send. See below | none |
CSV values appear exactly as they are in the file. Excel values appear the way the cell is formatted, such as $1,234.50, 12.5% or a date.
Placeholders
Use these in subject, intro and footer:
| Placeholder | Becomes |
|---|---|
{date} | October 15, 2026 |
{date:M/d/yyyy} | Any date format, here 10/15/2026 |
{weekday} | Thursday |
{month} | October 2026 |
{lastmonth} | September 2026 |
{rows} | Number of rows in the report |
{file} | The file name |
{report} | The report's name |
Schedules
After adding or changing a schedule, choose 3 in the menu.
| Schedule | Example |
|---|---|
| Every day | { "every": "day", "time": "7:00 AM" } |
| Weekdays (Mon–Fri) | { "every": "weekday", "time": "7:00 AM" } |
| Certain days of the week | { "every": "week", "days": ["Mon", "Thu"], "time": "8:00 AM" } |
| A day of the month (1 to 28) | { "every": "month", "day": 1, "time": "7:30 AM" } |
| Last day of the month | { "every": "month", "day": "last", "time": "5:00 PM" } |
Times can be "8:00 AM" or "08:00". To stop a report being scheduled, delete its "schedule" line, then choose 3.
Email setup
Report Emailer can send in two ways. Pick one and set "method" in reports.json.
| Classic Outlook | SMTP (Gmail and others) | |
|---|---|---|
| Best for | Offices on Microsoft 365 or Exchange | Gmail, Google Workspace, Zoho and similar |
| Passwords | None, uses your Outlook | An app password, stored encrypted |
| Needs | Classic Outlook installed on this PC | Nothing else |
| Sent emails appear in | Your Outlook Sent Items | Your provider's Sent folder (Gmail does this) |
Classic Outlook
- In
reports.json, set"method": "outlook". - That's it. Reports are sent from your default Outlook account and appear in Sent Items. To send from another account set up in Outlook, add
"outlook_account": "that@address.com".
Classic or new Outlook? Look at the top-right corner of Outlook. If you see a New Outlook switch turned on, you're using the new app, which no program can send through. Turn the switch off to go back to classic Outlook. If there's no switch and the window has File, Home and Send / Receive tabs, it's classic.
Outlook can be closed. Report Emailer opens it in the background and waits for the email to leave the Outbox, up to a minute. If an email ever sits in your Outbox, opening Outlook sends it.
Gmail or Google Workspace
Gmail needs an app password, a separate 16-letter password just for this program. Your normal Gmail password won't work.
- Turn on 2-Step Verification for the Google account, if it isn't already: myaccount.google.com → Security.
- Create the app password: go to myaccount.google.com/apppasswords, type a name like "Report Emailer", and click Create. Copy the 16-letter password. If the page says app passwords aren't available, your Google Workspace administrator has turned them off. Ask them, or use classic Outlook.
- In
reports.json, set: ``json "email": { "method": "smtp", "from": "you@gmail.com", "from_name": "Your Business Reports", "smtp_server": "smtp.gmail.com", "smtp_port": 587 } - In the menu, choose 5 and paste the app password. Nothing shows as you paste; that's normal. Press Enter.
The password is encrypted with Windows' built-in protection, so only your Windows account on this PC can use it. If you change PCs or Windows accounts, save it again.
Other email services
Any service that offers SMTP on port 587 with an app password works. Look for "SMTP settings" in your provider's help. For example, Zoho Mail uses smtp.zoho.com, port 587, with an app-specific password.
Port 465 isn't supported. Nearly every provider that offers 465 also offers 587.
Microsoft 365 and Outlook.com accounts
Microsoft is switching off password-based SMTP sending for Microsoft 365 business accounts. It is due to be off by default from the end of December 2026, and Outlook.com personal accounts already require Microsoft's newer sign-in. For these accounts, use classic Outlook.
Alerts
Add "alert_to": "you@yourbusiness.com" in the email settings to get a short email whenever a report is skipped (empty or out-of-date file) or can't be sent. Alerts are sent the same way as reports, so if email itself is broken, check the log (menu option 7).
Changelog
1.0.0 (2026-10-15)
First release.
- Runs on Windows 10 and 11 with nothing to install: PowerShell only, no Excel needed.
- Reads .xlsx (with cell formatting: currency, percentages, dates) and .csv (UTF-8 or Excel's Windows encoding; comma, semicolon or tab separated).
- Finds the file: a fixed file, or the newest matching file in a folder.
- Builds the email: your message, a table with chosen columns, totals, row limit with the full file attached, and a plain-text version.
- Sends through classic Outlook or SMTP (STARTTLS on port 587) with an app password encrypted for the Windows user.
- Schedules daily, weekday, weekly or monthly runs in Windows Task Scheduler, catching up after the PC was off.
- Safety checks: skips empty or out-of-date files, emails an alert, and keeps a log.
- Preview any report in the browser before sending.
- A double-click menu for everything.