Build a Sales Report Robot with Python and Polars: Day 2 - Email the Report and Run It Every Monday
The first part of this video is free. Paid members watch the full video and get the complete code for this week’s project, plus every past Day 2 project.
Build a Sales Report Robot with Python and Polars: Day 2 - Email the Report and Run It Every Monday
The robot now sends the PDF by email and runs by itself every Monday, on Windows, Mac and Linux.
Yesterday we turned four Excel files into a PDF report with Polars. Today the robot sends that PDF by email, and the computer starts it by itself every Monday morning.
The video above explains the whole week: how the robot adds up the files, how Python sends an email, and how your computer knows that it is Monday.
Projects in this week’s series:
Day 1: Yesterday, we merged a folder of Excel files with Polars and turned the totals into a PDF report.
Day 2 (Today): The robot sends the report by email, and we schedule it to run every Monday on Windows, Mac and Linux.
Get the data
We use the same four Excel files as yesterday. If you don’t have them yet, download them from yesterday’s post and put them in a folder called sales, next to the code.
The output
Every Monday at 8:00, this email arrives with the PDF report attached:
The subject has the dates of the week, and the text has the total revenue and the best region. Nobody has to open a terminal for it.
What you get today
The PDF report sent by email, with the totals in the email text
Your email address and app password kept in a .env file, outside the code
A log file, robot.log, that records every run
One command that runs the robot every Monday, on Windows, Mac and Linux
The key idea
Sending an email from Python takes two steps. First you build the message, and then you hand it to your email provider’s server. These are the main lines of send_email() in emailer.py:
message = EmailMessage()
message['From'] = EMAIL_ADDRESS
message['To'] = to
message['Subject'] = subject
message.set_content(body)
with smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT) as server:
server.login(EMAIL_ADDRESS, EMAIL_APP_PASSWORD)
server.send_message(message)An EmailMessage works like a form. You fill in who it is from, who it is to, the subject and the text. Between these two parts, add_attachment() puts the PDF into the message.
Then SMTP_SSL opens an encrypted connection to Gmail’s mail server, smtp.gmail.com, on port 465. The robot logs in and sends the message. The address and the password come from the .env file, so they are never written inside the code.
Worth knowing
Gmail only accepts an app password here, and Google only gives you one when 2-Step Verification is turned on for your account. You create it at myaccount.google.com/apppasswords.
A scheduler does not start the robot in your project folder. That is why main.py builds every path from
BASE_DIR, the folder of main.py itself. This way it finds the sales folder and the .env file wherever it is started from.On a Mac, cron may not be allowed to read your Desktop, Documents and Downloads folders, and the robot then stops with “Operation not permitted”. Keep the project in a folder like ~/report_robot, or give cron Full Disk Access in System Settings.
Run it
Put main.py, emailer.py and .env.example from the solution below into one folder, next to the sales folder. Then:
Install the libraries:
pip install polars fastexcel matplotlib fpdf2 python-dotenvRename .env.example to .env, and fill in your Gmail address, your app password and the address that should get the report.
Run it once by hand with
python main.pyand check your inbox.Schedule it with one command, using the full paths to Python and to main.py:
# Windows (Command Prompt)
schtasks /create /tn "Report Robot" /sc weekly /d MON /st 08:00 /tr "C:\path\to\python.exe C:\path\to\main.py"
# Mac and Linux: run crontab -e and add this line
0 8 * * 1 /path/to/python3 /path/to/main.pyTo find the full path to your Python, run where python on Windows or which python3 on Mac and Linux. This is what the cron line means:
After a scheduled run, robot.log shows every step the robot took:
Try this
Add the best product to the email text, next to the best region. You can take it from product_totals in the same way best comes from region_totals. Which product made the most revenue last week? Reply and tell me.
Solution
The full code is below. There are three files: main.py, emailer.py and .env.example. Every step in main.py has a comment...
Watch with a 7-day free trial
Subscribe to Daily Python Projects to watch this video and get 7 days of free access to the full post archives.
A subscription gets you:
© 2026 Ardit Sulce
[email protected]