Application/Python

[Python] 13. 파이썬 이메일 자동 발송: smtplib 기초

devsalix 2026. 7. 10. 11:01
728x90

파이썬 이메일 자동 발송: smtplib 기초

지난 글에서 공문 30장을 코드로 순식간에 찍어냈잖아요. 그런데 다 만들고 나면 바로 이 생각이 들죠.

"이걸 또 30명한테 일일이 메일로 보내야 하나…"

매일 아침 똑같은 보고 메일, 매주 똑같은 안내 메일을 받는 사람만 바꿔가며 복붙해서 보내는 그 노동. 오늘은 그걸 파이썬한테 시킬 거예요.

사실 이 글부터 파이썬이 하는 일이 좀 달라져요. 지금까지는 내 컴퓨터 안에서 파일을 만들고 저장했다면, 오늘부터는 만든 걸 바깥세상(인터넷)으로 내보내기 시작하거든요. 그 첫걸음이 이메일이에요.


이번엔 설치할 게 없어요 (python smtplib는 기본 내장)

먼저 반가운 소식 하나. 엑셀 다룰 때 openpyxl 깔고, 워드 다룰 때 python-docx 깔면서 이름 헷갈려 고생하셨잖아요. 이번엔 그럴 일 없어요.

메일 보내는 도구는 파이썬에 처음부터 들어 있거든요.

import smtplib                            # 메일을 '보내는' 도구 (기본 내장)
from email.message import EmailMessage    # 메일 '내용'을 담는 편지 봉투 (기본 내장)

 

pip install 안 해도 됩니다. 그냥 바로 써요.


메일 보내는 원리, 딱 3단계

코드가 무서워 보일까 봐 미리 큰 그림을 그려 드릴게요. 파이썬이 메일을 보내는 건 결국 이 흐름이에요.

  1. 편지 쓰기 — 제목, 받는 사람, 본문을 봉투에 담아요 (EmailMessage)
  2. 우체국 접속 + 신분 확인 — 메일 서버(우체국)에 연결하고 "나 이 계정 주인 맞아요" 로그인해요
  3. 부치기 — 편지를 창구에 밀어 넣어요. 나머지 배달은 서버가 알아서 해줘요

내가 직접 상대방 집까지 편지를 배달하는 게 아니라, 우체국에 가져다 부치면 우체국이 알아서 배송하는 거랑 똑같아요. 파이썬은 편지를 써서 창구에 내밀 뿐이에요.

오늘 코드는 전부 이 3단계의 변주일 뿐이에요.


진짜 관문은 코드가 아니라 앱 비밀번호예요

솔직하게 미리 말씀드릴게요. smtplib 코드 자체는 10줄이면 끝나요. 진짜 어려운 건 딱 하나, Gmail 앱 비밀번호예요.

저도 처음에 평소 쓰던 Gmail 비밀번호를 코드에 넣고 계속 안 돼서 30분을 헤맸거든요. 알고 보니 Gmail은 보안 때문에 외부 프로그램이 진짜 계정 비밀번호로 로그인하는 걸 막아놨더라고요. 대신 "이 프로그램만 쓸 수 있는 임시 출입증" 을 따로 발급해줘요. 그게 앱 비밀번호예요.

회사 정문에 내 진짜 신분증을 아무 프로그램한테나 맡기면 위험하잖아요. 그래서 방문객용 임시 출입증만 하나 파주는 거예요. 진짜 열쇠는 계속 내가 갖고요.


앱 비밀번호 만드는 순서

이 순서 그대로 따라오시면 돼요.

  1. 구글 계정 2단계 인증부터 켜요. (이게 제일 중요해요)
    • 구글 계정 → 보안 → "2단계 인증"을 사용으로 바꿔요.
    • 이걸 안 켜면 앱 비밀번호 메뉴 자체가 안 보여요. "앱 비밀번호가 어디 있죠?" 질문의 99%가 이거예요. 금고 문을 열어야 그 안에 있는 서랍이 보이는 거랑 같아요.
  2. 앱 비밀번호를 발급받아요.
    • 구글 계정 보안 화면에서 "앱 비밀번호"를 검색해서 들어가요.
    • 이름을 아무거나(예: "파이썬 메일") 지정하고 생성.
  3. 16자리 문자열이 나와요.
    • abcd efgh ijkl mnop처럼 네 자리씩 띄어져 보이는데, 띄어쓰기는 눈에 편하라고 나눈 거예요. 그냥 공백 빼고 붙여서 쓰셔도 돼요.
    • 이 창을 닫으면 다시 못 보니까 바로 복사해 두세요.

이제 이 16자리를 코드의 비밀번호 자리에 넣을 거예요. 평소 로그인 비번이 아니라, 방금 발급받은 이 16자리요. 이거 하나 때문에 대부분 막히니까 꼭 기억해 두세요.


나에게 테스트 메일 한 통 보내기

준비 끝났으면 이제 진짜 보내볼게요. 첫 실험은 무조건 나 자신에게 보내는 거예요. 받은편지함에 딱 도착하는 순간, 절반은 끝난 거예요.

import smtplib
from email.message import EmailMessage    # 둘 다 기본 내장

# 1) 편지 만들기
msg = EmailMessage()                          # 빈 봉투 한 장
msg["Subject"] = "파이썬으로 보낸 첫 메일"      # 제목
msg["From"] = "mysender@gmail.com"            # 보내는 사람 (내 Gmail)
msg["To"] = "mysender@gmail.com"              # 받는 사람 (테스트니까 나 자신)
msg.set_content("이 메일이 오면 성공입니다!")   # 본문

# 2) 우체국 접속 → 암호화 → 로그인 → 발송
with smtplib.SMTP("smtp.gmail.com", 587) as server:   # Gmail 서버에 접속
    server.starttls()                                 # 안전한 통로 켜기 (필수)
    server.login("mysender@gmail.com", "앱비밀번호16자리")  # 앱 비번!
    server.send_message(msg)                          # 편지 부치기

print("메일 발송 완료! 받은편지함을 확인하세요.")

# 실행 결과:
# 메일 발송 완료! 받은편지함을 확인하세요.

 

몇 가지 짚어 볼게요.

msg["Subject"], msg["To"]처럼 대괄호에 값을 넣는 건 봉투 겉면에 제목이랑 주소를 쓰는 거예요. 그런데 본문만은 msg.set_content("...") 라는 전용 메서드로 넣어요. 여기서 msg["Body"]라고 쓰는 분들이 많은데, 그러면 본문이 텅 빈 채로 발송돼요.

with smtplib.SMTP(...) as server: 이 부분은 파일 다룰 때 배운 with open(...)이랑 똑같은 안전장치예요. 발송이 끝나거나 에러가 나도 서버 연결을 알아서 정리해줘요.

그리고 순서가 중요해요. 접속 → starttls() 암호화 → login → 발송, 이 순서를 절대 바꾸면 안 돼요. 특히 starttls()는 로그인보다 먼저 와야 해요.


비밀번호를 코드에서 빼내기 (.env 분리)

한 통 보내는 데 성공하셨나요? 그럼 좋은 습관 하나 알려드릴게요.

방금 코드에 앱 비밀번호를 그대로 적었잖아요. 당장은 되는데, 이 코드를 누구한테 보내거나 깃허브에 올리면 비밀번호가 그대로 노출돼요. 그러면 남이 내 계정으로 메일을 보낼 수 있어요.

그래서 비밀 값만 따로 .env 파일에 빼놓는 방법이 있어요.

# .env 파일 (코드와 같은 폴더에, 절대 공유 금지!)
EMAIL_ADDRESS=mysender@gmail.com
EMAIL_PASSWORD=앱비밀번호16자리

 

import os, smtplib
from email.message import EmailMessage
from dotenv import load_dotenv     # pip install python-dotenv (설치명은 python-dotenv, 임포트는 dotenv)

load_dotenv()                              # .env 파일 읽어오기
my_email = os.getenv("EMAIL_ADDRESS")      # 주소 꺼내기
my_pw = os.getenv("EMAIL_PASSWORD")        # 앱 비번 꺼내기

# ... server.login(my_email, my_pw) 로 사용

 

이렇게 하면 코드 어디에도 비밀번호가 안 보여요. 여기서만 유일하게 python-dotenv 하나를 설치하는데, 이건 선택이에요. 일단 직접 넣어서 성공부터 하고, 그다음에 옮기셔도 돼요.


여러 명에게 한 번에 보내기 (이메일 자동화의 진짜 시작)

이제 진짜 하고 싶었던 거요. 여러 명한테 보낼 때는 To에 리스트를 그냥 넣으면 안 되고, 콤마로 이어 붙인 문자열로 만들어야 해요.

받는사람들 = ["a@example.com", "b@example.com", "c@example.com"]

msg["To"] = ", ".join(받는사람들)   # 리스트를 "a@..., b@..., c@..." 한 문자열로

 

", ".join(리스트)는 리스트를 콤마로 이어서 하나의 문자열로 합쳐줘요. 한 번에 여러 명이 받게 되는 거죠.

그런데 각자한테 이름을 넣은 다른 내용을 보내고 싶다면? 그땐 반복문으로 한 명씩 돌리면 돼요. (엑셀 명단 읽어오던 감각이랑 이어져요.)

people = [
    {"name": "김영희", "email": "younghee@example.com"},
    {"name": "박철수", "email": "chulsoo@example.com"},
]

with smtplib.SMTP("smtp.gmail.com", 587) as server:   # 접속·로그인은 한 번만
    server.starttls()
    server.login("mysender@gmail.com", "앱비밀번호16자리")

    for person in people:                          # 한 사람씩
        msg = EmailMessage()                       # 사람마다 새 봉투
        msg["Subject"] = "안내 말씀"
        msg["From"] = "mysender@gmail.com"
        msg["To"] = person["email"]                # 이 사람에게만
        msg.set_content(f"{person['name']}님, 안녕하세요. 확인 부탁드려요.")
        server.send_message(msg)
        print(f"{person['name']}님에게 발송 완료")

# 실행 결과:
# 김영희님에게 발송 완료
# 박철수님에게 발송 완료

 

접속이랑 로그인은 반복문 밖에서 딱 한 번만 하고, 편지만 사람마다 새로 만들어요. f-string으로 이름을 쏙 넣는 것도 보이시죠.

한 가지만 주의하세요. 짧은 시간에 너무 많이 보내면 Gmail이 스팸으로 보고 막아요. 하루 발송 한도가 있거든요. 실습으로 몇 명~수십 명 정도는 전혀 문제없어요.


실전: 보고서 완료 알림 메일

문서 파트에서 배운 거랑 이어보면 이런 것도 돼요. 보고서를 다 만든 뒤에 "완료됐다"고 상사한테 자동으로 알려주는 거요.

import smtplib
from email.message import EmailMessage
from datetime import datetime

오늘 = datetime.now().strftime("%Y-%m-%d")   # 오늘 날짜 문자열

msg = EmailMessage()
msg["Subject"] = f"[자동] {오늘} 일일 보고서 생성 완료"
msg["From"] = "mysender@gmail.com"
msg["To"] = "boss@example.com"
msg.set_content(f"{오늘} 자 보고서 생성이 완료되었습니다.\n확인 부탁드립니다.")

with smtplib.SMTP("smtp.gmail.com", 587) as server:
    server.starttls()
    server.login("mysender@gmail.com", "앱비밀번호16자리")
    server.send_message(msg)

print("완료 알림 메일 발송!")

 

문서를 만드는 코드 뒤에 이걸 붙이면, 파이썬이 일 끝내고 스스로 보고까지 하는 셈이에요.

참고로 네이버 메일을 쓰신다면 서버 주소만 smtp.naver.com(포트 587)으로 바꾸면 되는데, 네이버는 메일 환경설정에서 "SMTP 사용"을 먼저 켜야 발송돼요. 기본이 꺼져 있거든요. Gmail의 앱 비밀번호 같은 관문이라고 보시면 돼요.


이 에러 뜨면 코드 말고 비밀번호를 의심하세요

십중팔구 이 에러를 만나실 거예요.

smtplib.SMTPAuthenticationError: (535, b'5.7.8 Username and Password not accepted ...')

 

앞에 뜨는 535, 이 숫자가 보이면 거의 다 앱 비밀번호 문제예요. 코드가 맞는데도 이게 뜨면 이 순서로 확인하세요.

  1. 평소 Gmail 비밀번호를 넣진 않았나요? → 앱 비밀번호 16자리로 바꾸세요. (제일 흔한 원인)
  2. 2단계 인증은 켜져 있나요? → 안 켜면 앱 비밀번호가 아예 안 만들어져요.
  3. 앱 비밀번호에 오타는 없나요? → 화면에서 다시 복사하세요. 공백은 빼도 돼요.

"코드가 아니라 비밀번호를 의심하라." 이 한마디만 기억하셔도 이 에러의 90%는 스스로 해결하실 수 있어요.


직접 해보기

  • 앞의 순서대로 2단계 인증 켜고 앱 비밀번호 발급까지 완료해 보세요. (제일 큰 산이에요)
  • 나 자신에게 테스트 메일 한 통 보내서 받은편지함에서 확인해 보세요. 이게 성공하면 절반은 끝난 거예요.
  • 본인 계정이랑 가족/동료 2~3명에게 같은 안내 메일을 한 번에 보내 보세요. (힌트: ", ".join())

막히시면 대부분 앱 비밀번호 문제니까, 에러의 535 숫자부터 확인해 보세요.


 

여기까지 오셨으면, 이제 파이썬이 만든 걸 내 컴퓨터 밖으로 내보낼 수 있게 된 거예요. 그 첫 대상이 이메일이었고요.

그런데 오늘 보낸 건 밋밋한 텍스트 메일이잖아요. 실무에선 엑셀이나 PDF 파일을 첨부하거나, 표와 색이 들어간 예쁜 메일을 보내야 할 때가 많죠. 다음 글에서는 파이썬으로 파일 첨부하고 HTML로 꾸며서 보내는 법을 다뤄볼 거예요.

그리고 지난 글에서 배운 '양식 채워서 문서 일괄 생성'과 오늘 배운 '메일 자동 발송'이 만나면, 명단만 넣으면 개인별 문서를 만들어서 각자에게 메일까지 보내는 시스템이 돼요. 그건 이 파트 미니 프로젝트에서 합쳐볼게요.


 


제 글이 도움이 되셨다면 댓글 & 공감 부탁드려요 😀

 

 
728x90