연체 결제 추적을 자동화했습니다 (스크립트 공개)

발행: (2026년 3월 31일 AM 12:35 GMT+9)
5 분 소요
원문: Dev.to

Source: Dev.to

프리랜서를 한 달 이상 해왔다면, 이런 상황을 겪어봤을 겁니다: 청구서를 보냈지만, 기한이 지나고, 답이 없을 때.
후속 이메일은 한 번만 쓰면 쉽지만, 모든 클라이언트에게 정기적으로 작성하는 것은 번거롭습니다. 그래서 대부분의 사람들은 하지 않으며, 그 결과 늦은 결제가 계속됩니다.

제가 자동화했습니다.

스크립트가 하는 일

스크립트는 청구서 CSV(고객 이름, 금액, 마감일, 이메일, 상태)를 읽습니다. 하루에 한 번, 연체된 청구서를 확인하고 단계에 맞는 이메일을 보냅니다:

  • Day 1 overdue – 친근한 알림, 따뜻한 어조
  • Day 7 – 직접적인 요청, 청구서 재첨부
  • Day 14 – 더 단호하게, 이전 이메일을 언급
  • Day 30 – 에스컬레이션 전 최종 통보

템플릿은 한 번만 설정하면 됩니다. 스크립트가 주기를 자동으로 관리합니다.

핵심 로직 (invoice_followup.py)

# invoice_followup.py — core logic
import csv, smtplib, datetime
from email.mime.text import MIMEText

STAGES = [
    (1,  "just checking in",     "warm"),
    (7,  "following up again",   "direct"),
    (14, "third notice",         "firm"),
    (30, "final notice",         "formal"),
]

def days_overdue(due_date_str):
    due = datetime.date.fromisoformat(due_date_str)
    return (datetime.date.today() - due).days

def should_send_today(days, last_sent_days):
    """Returns the stage template if today is a follow‑up day."""
    for threshold, subject_suffix, tone in STAGES:
        if days >= threshold and last_sent_days < threshold:
            return subject_suffix, tone
    return None, None

def run(invoices_csv, gmail_user, gmail_app_password):
    with open(invoices_csv) as f:
        rows = list(csv.DictReader(f))

    for row in rows:
        if row['status'] != 'unpaid':
            continue

        days = days_overdue(row['due_date'])
        last_sent = int(row.get('last_followup_days', 0) or 0)
        subject_suffix, tone = should_send_today(days, last_sent)

        if not subject_suffix:
            continue

        body = render_template(tone, row)
        send_email(
            gmail_user, gmail_app_password,
            to=row['client_email'],
            subject=f"Invoice {row['invoice_id']}{subject_suffix}",
            body=body
        )
        row['last_followup_days'] = days
        print(f"Sent {tone} follow‑up to {row['client_name']}")

    # Write updated CSV back
    with open(invoices_csv, 'w', newline='') as f:
        writer = csv.DictWriter(f, fieldnames=rows[0].keys())
        writer.writeheader()
        writer.writerows(rows)

render_template 함수는 고객 이름, 금액 및 마감일을 채워 넣습니다. 청구서가 오래될수록 어조가 “친근함”에서 “격식”으로 자동 전환됩니다.

Setup (≈ 10 minutes)

  1. 인보이스를 CSV로 내보내기 (형식은 자유—스크립트를 수정할 수 있음).

  2. Gmail 앱 비밀번호 생성 (2FA 필요, 약 2 분 소요).

  3. 한 번 실행:

    python3 invoice_followup.py invoices.csv
  4. 매일 실행되도록 cron에 추가:

    0 9 * * * python3 /path/to/invoice_followup.py invoices.csv

그게 전부입니다. SaaS도, 구독도, 월 요금도 없습니다—당신의 머신에서 실행되고, 자신의 Gmail로 이메일을 보내는 스크립트일 뿐입니다.

맞춤 설정 옵션

  • 청구서 도구 – FreshBooks, Wave, Bonsai, plain CSV, Notion 데이터베이스
  • 이메일 제공자 – Gmail, Outlook, 맞춤 SMTP
  • 에스컬레이션 로직 – 다양한 임계값, 톤, 30일 차에 제3자를 CC
  • WhatsApp 또는 SMS – 이메일 대신 Twilio를 통해 전송
  • Slack 알림 – 후속 조치가 전송되거나 결제가 도착했을 때 자신에게 알림

가격: $25 고정. 48시간 내 전달. 무료 수정 1회.

일반 버전을 그대로 원하시면 무료입니다 — 댓글에 요청해 주시면 전체 스크립트를 보내드리겠습니다.

어떻게 구할 수 있나요

  • 무료 버전 (일반): 아래에 댓글을 달거나 citriac@outlook.com 으로 이메일을 보내 주세요 — 전체 스크립트를 보내드리겠습니다.
  • 맞춤 버전 ($25): citriac.github.io/hire — 설정을 설명해 주세요; 24시간 이내에 견적을 드리겠습니다.

관련: The Boring Work That Eats Your Freelance Hours — 프리랜서를 위해 자동화하는 다른 반복 작업들.

0 조회
Back to Blog

관련 글

더 보기 »