
IT·디지털 자동화 블로그 · 파이썬 업무 효율화
왜 메일 발송 자동화인가
보고서 생성 후 메일로 공유하는 업무는 대부분 반복적입니다. 수동 전송은 누락과 지연을 낳고, 파일명·수신자·본문 포맷도 매번 손봐야 합니다. 파이썬으로 자동화하면 일정에 맞춰 최신 보고서를 생성하고, 표준화된 본문과 제목으로 신속하게 발송할 수 있습니다. 오류 발생 시 로그로 추적하고 재시도 전략까지 더하면 운영 안정성이 높아집니다.
환경 준비와 보안 변수
필수 패키지
pip install pandas openpyxl
보안 변수 설정
계정 비밀번호나 앱 비밀번호는 코드에 직접 쓰지 말고 환경 변수로 관리합니다.
# 예시 (Windows PowerShell)
setx MAIL_USER "your_account@example.com"
setx MAIL_PASS "app_password_or_token"
회사 정책에 따라 SMTP 앱 비밀번호 또는 OAuth를 사용합니다. 사내 메일 서버를 쓰는 경우 보안팀 가이드에 맞춰 포트·암호화 방식을 확인하세요.
엑셀 보고서 자동 생성
pandas로 요약표를 만들고 openpyxl 엔진으로 저장합니다. 실제 데이터 소스(API·DB·CSV)를 연결해도 구조는 같습니다.
# file: make_report.py
import pandas as pd
from datetime import datetime
# 1) 샘플 데이터 생성(실무에서는 DB/CSV/API로 대체)
df = pd.DataFrame({
"월": ["1월","2월","3월","4월","5월","6월"],
"매출": [120,150,180,160,210,240],
"비용": [80,90,110,100,120,140]
})
df["이익"] = df["매출"] - df["비용"]
# 2) 요약표
summary = df.agg({"매출":["sum","mean"], "비용":["sum","mean"], "이익":["sum","mean"]})
summary = summary.rename(index={"sum":"합계","mean":"평균"})
# 3) 저장
stamp = datetime.now().strftime("%Y%m%d")
file_name = f"월별_보고서_{stamp}.xlsx"
with pd.ExcelWriter(file_name, engine="openpyxl") as writer:
df.to_excel(writer, index=False, sheet_name="원본")
summary.to_excel(writer, sheet_name="요약")
print("보고서 생성 완료:", file_name)
이메일 본문 구성과 첨부
EmailMessage를 사용하면 텍스트와 HTML 본문, 첨부 파일을 간단히 구성할 수 있습니다. 제목에는 날짜 스탬프를 포함해 버전 관리가 쉬운 형태를 권장합니다.
# file: send_mail.py
import os, mimetypes, smtplib, time
from email.message import EmailMessage
from datetime import datetime
MAIL_USER = os.getenv("MAIL_USER")
MAIL_PASS = os.getenv("MAIL_PASS")
def build_message(to_addrs, subject, body_text, body_html, attachments):
msg = EmailMessage()
msg["From"] = MAIL_USER
msg["To"] = ", ".join(to_addrs)
msg["Subject"] = subject
# 멀티파트: 기본 텍스트 + HTML
msg.set_content(body_text)
msg.add_alternative(body_html, subtype="html")
for path in attachments:
ctype, _ = mimetypes.guess_type(path)
maintype, subtype = (ctype or "application/octet-stream").split("/", 1)
with open(path, "rb") as f:
msg.add_attachment(f.read(),
maintype=maintype,
subtype=subtype,
filename=os.path.basename(path))
return msg
if __name__ == "__main__":
today = datetime.now().strftime("%Y-%m-%d")
report = sorted([f for f in os.listdir(".") if f.startswith("월별_보고서_")])[-1]
subject = f"[주간 보고] 월별 실적 요약 {today}"
body_text = f"""팀 여러분,
첨부된 엑셀 파일에서 월별 매출·비용·이익 요약을 확인하세요.
자동 발송 시각: {today}
"""
body_html = f"""
팀 여러분,
첨부된 엑셀 파일에서 월별 매출·비용·이익 요약을 확인하세요.
- 자동 발송 시각: {today}
- 문의: 데이터운영팀
감사합니다.
"""
msg = build_message(
to_addrs=["recipient1@example.com","recipient2@example.com"],
subject=subject,
body_text=body_text,
body_html=body_html,
attachments=[report]
)
# SMTP 연결은 아래 섹션의 설정을 참고해 호출합니다.
SMTP 설정(Gmail·네이버·Outlook)
Gmail 예시(TLS 587)
def send_via_gmail(msg):
with smtplib.SMTP("smtp.gmail.com", 587, timeout=30) as smtp:
smtp.ehlo()
smtp.starttls()
smtp.login(MAIL_USER, MAIL_PASS) # 앱 비밀번호 권장
smtp.send_message(msg)
print("Gmail 발송 완료")
네이버·Outlook 예시
def send_via_naver(msg):
with smtplib.SMTP("smtp.naver.com", 587, timeout=30) as s:
s.starttls(); s.login(MAIL_USER, MAIL_PASS); s.send_message(msg)
def send_via_outlook(msg):
with smtplib.SMTP("smtp.office365.com", 587, timeout=30) as s:
s.starttls(); s.login(MAIL_USER, MAIL_PASS); s.send_message(msg)
사내 SMTP는 IT 정책에 따라 호스트와 포트를 확인해야 합니다. SPF·DKIM·DMARC 설정이 필요한 도메인의 경우 메일 인프라 담당자와 협의하세요.
로깅·재시도·예외 처리
네트워크 일시 장애나 수신자 주소 오류 등 현실적 이슈에 대비해 재시도와 로그를 남기는 것이 좋습니다.
# file: send_with_retry.py
import logging, smtplib, time
from send_mail import build_message, MAIL_USER, MAIL_PASS
logging.basicConfig(filename="mail_log.txt",
level=logging.INFO,
format="%(asctime)s %(levelname)s %(message)s")
def send_with_retry(msg, max_attempts=3, backoff=5):
attempt = 0
while attempt < max_attempts:
try:
with smtplib.SMTP("smtp.gmail.com", 587, timeout=30) as s:
s.starttls()
s.login(MAIL_USER, MAIL_PASS)
s.send_message(msg)
logging.info("메일 발송 성공: %s", msg["Subject"])
return True
except Exception as e:
attempt += 1
logging.warning("발송 실패(%d/%d): %s", attempt, max_attempts, e)
time.sleep(backoff * attempt)
logging.error("최종 실패: %s", msg["Subject"])
return False
로그 파일은 운영 이슈 파악과 대응 속도를 개선합니다. 필요하다면 실패 알림을 슬랙·팀즈 웹훅으로도 보내도록 확장하세요.
자동 실행 스케줄링
Windows 작업 스케줄러
- 작업 스케줄러 열기 → 작업 만들기
- 트리거: 매일 08:55 시작
- 동작: 프로그램 시작 → python 경로와 스크립트 지정
macOS·Linux 크론
# 매일 08:55에 실행
55 8 * * * /usr/bin/python3 /path/make_report.py && /usr/bin/python3 /path/send_with_retry.py
보고서 생성 후 발송 순서로 연결하면 최신 파일이 자동으로 첨부됩니다.
체크리스트
- 엑셀 보고서가 날짜 스탬프 파일명으로 생성되는가
- 메일 제목·본문 템플릿이 표준화되어 있는가
- 환경 변수로 계정 정보가 안전하게 관리되는가
- 로그 파일과 재시도 로직이 동작하는가
- 스케줄러 등록으로 무중단 운영이 가능한가
다음 글 예고: PDF 보고서 변환과 수신자 그룹 관리
다음 편에서는 엑셀을 PDF로 자동 변환하고, 팀·경영진 등 수신자 그룹별 템플릿을 달리 적용하는 고급 자동화를 다룹니다.
관련 읽을거리: 매일 자동 보고서 만들기 · 엑셀 시트 자동 생성