DEV Community

Brad
Brad

Posted on

5 Python Scripts Every Freelancer Should Run on Autopilot

I've been freelancing for 4 years. The biggest lesson: admin work will eat you alive if you let it.

Chasing invoices. Sending project updates. Tracking billable hours. Following up on proposals. Writing weekly reports.

None of it makes you money directly. All of it is necessary. The solution: automate it.

Here are the 5 scripts I run on autopilot every week.

1. Automatic Invoice Follow-Up

Checks your invoice records and sends a polite follow-up if payment is 7+ days late.

import smtplib
import csv
from datetime import datetime, timedelta
from email.mime.text import MIMEText

def check_overdue_invoices(invoices_file="invoices.csv"):
    overdue = []
    today = datetime.now().date()

    with open(invoices_file) as f:
        reader = csv.DictReader(f)
        for row in reader:
            if row["status"] == "unpaid":
                due_date = datetime.strptime(row["due_date"], "%Y-%m-%d").date()
                days_overdue = (today - due_date).days
                if days_overdue > 7:
                    overdue.append({**row, "days_overdue": days_overdue})
    return overdue

def send_followup(invoice, email_from, email_password):
    body = f"Hi {invoice['client_name']},\n\nFollowing up on invoice #{invoice['invoice_id']} for ${invoice['amount']}.\n\nCould you let me know the payment status?\n\nThanks"
    msg = MIMEText(body)
    msg["Subject"] = f"Follow-up: Invoice #{invoice['invoice_id']} ({invoice['days_overdue']} days overdue)"
    msg["From"] = email_from
    msg["To"] = invoice["client_email"]

    with smtplib.SMTP_SSL("smtp.gmail.com", 465) as server:
        server.login(email_from, email_password)
        server.sendmail(email_from, invoice["client_email"], msg.as_string())
    print(f"Follow-up sent for Invoice #{invoice['invoice_id']}")

overdue = check_overdue_invoices()
for inv in overdue:
    send_followup(inv, "your@email.com", "your-app-password")
Enter fullscreen mode Exit fullscreen mode

CSV columns: invoice_id, client_name, client_email, amount, due_date, status

2. Time Tracker to Weekly Report

Reads your time logs and generates a client-ready weekly summary automatically.

from collections import defaultdict
from datetime import datetime, timedelta
import csv

def generate_weekly_report(time_log="time_log.csv"):
    week_ago = datetime.now() - timedelta(days=7)
    client_hours = defaultdict(list)

    with open(time_log) as f:
        for row in csv.DictReader(f):
            date = datetime.strptime(row["date"], "%Y-%m-%d")
            if date >= week_ago:
                client_hours[row["client"]].append({
                    "date": row["date"],
                    "task": row["task"],
                    "hours": float(row["hours"])
                })

    report = f"Weekly Report - Week of {week_ago.strftime('%B %d')}\n"
    report += "=" * 50 + "\n\n"

    for client, entries in client_hours.items():
        total = sum(e["hours"] for e in entries)
        report += f"Client: {client} | Total: {total:.1f} hours\n"
        for e in entries:
            report += f"  {e['date']} - {e['task']} ({e['hours']}h)\n"
        report += "\n"

    filename = f"report_{datetime.now().strftime('%Y%m%d')}.txt"
    with open(filename, "w") as f:
        f.write(report)
    print(f"Report saved to {filename}")

generate_weekly_report()
Enter fullscreen mode Exit fullscreen mode

3. Proposal Follow-Up Tracker

Tracks sent proposals and reminds you to follow up at day 3, 7, and 14.

import csv
from datetime import datetime

def check_pending_proposals(proposals_file="proposals.csv"):
    today = datetime.now().date()

    with open(proposals_file) as f:
        for row in csv.DictReader(f):
            if row["status"] == "sent":
                sent_date = datetime.strptime(row["sent_date"], "%Y-%m-%d").date()
                days_since = (today - sent_date).days

                if days_since in [3, 7, 14]:
                    print(f"\n📧 Follow up on day {days_since}:")
                    print(f"   Client: {row['client']}")
                    print(f"   Project: {row['project']}")
                    print(f"   Value: ${row['amount']}")

check_pending_proposals()
Enter fullscreen mode Exit fullscreen mode

4. Daily Earnings Snapshot

Calculates your actual hourly rate and daily earnings. Useful reality check.

import csv
from datetime import datetime

def daily_earnings(time_log="time_log.csv"):
    today = datetime.now().strftime("%Y-%m-%d")
    total_hours = 0
    total_earned = 0

    with open(time_log) as f:
        for row in csv.DictReader(f):
            if row["date"] == today:
                hours = float(row["hours"])
                rate = float(row.get("rate", 0))
                total_hours += hours
                total_earned += hours * rate

    rate = total_earned / total_hours if total_hours > 0 else 0
    print(f"Today: {total_hours:.1f}h worked | ${total_earned:.2f} earned | ${rate:.2f}/hr")

daily_earnings()
Enter fullscreen mode Exit fullscreen mode

5. Client Relationship Greeter

Sends birthday and work-anniversary messages to clients automatically.

import csv
import smtplib
from datetime import datetime
from email.mime.text import MIMEText

def check_client_occasions(clients_file="clients.csv", email_from="", email_password=""):
    today = datetime.now()

    with open(clients_file) as f:
        for row in csv.DictReader(f):
            if row.get("birthday"):
                bday = datetime.strptime(row["birthday"], "%Y-%m-%d")
                if bday.month == today.month and bday.day == today.day:
                    send_greeting(row, "birthday", email_from, email_password)

def send_greeting(client, occasion, email_from, email_password):
    body = f"Hi {client['name']},\n\nHappy {occasion}! Hope you're having a great day.\n\nBest"
    msg = MIMEText(body)
    msg["Subject"] = f"Happy {occasion.capitalize()}, {client['name']}!"
    msg["From"] = email_from
    msg["To"] = client["email"]

    with smtplib.SMTP_SSL("smtp.gmail.com", 465) as server:
        server.login(email_from, email_password)
        server.sendmail(email_from, client["email"], msg.as_string())

check_client_occasions()
Enter fullscreen mode Exit fullscreen mode

Running All 5 Together

# Every weekday morning at 8am
0 8 * * 1-5 cd ~/scripts && python invoice_followup.py && python weekly_report.py && python proposals.py && python earnings.py && python client_occasions.py
Enter fullscreen mode Exit fullscreen mode

Want the Full Toolkit?

I spent two years building polished versions of these with error handling, HTML email templates, logging, and 7 more scripts.

The Python Business Automation Toolkit has 12 scripts total for $29. The 5 above are yours free — the toolkit has the production-ready versions plus expense categorization, inventory alerts, payment reminders, and more.


Which of these would save you the most time? Let me know in the comments.

Top comments (0)