SMTP
: 메일 발송을 위해 메일 서비스 제공 회사와 사용자 간에 약속된 규약 (Simple Mail Transfer Protocol)IMAP
: 전자 메일에 엑세스 (Internet Messaging Access Protocol)POP
: 사용자 기기에 이메일 다운로드 후 삭제 (Post Office Protocol)
- 다른 이메일 제공 업체 서버
{p}.gmail.com
{p}.gmail.com
{p}.gmail.com
- 포트
465 :SMTP
993 :IMAP
995 :POP
SMTP_SERVER = 'smtp.naver.com' # 서버 주소
SMTP_PORT = 465 # 포트번호
SMTP_USER = 'email_addrs' # 유저네임
SMTP_PASSWORD = '*********' # 패스워드
SMTP_PASSWORD
같은 경우는 실제 비밀번호를 사용하기 때문에 email_config
처럼 따로 파일을 두고 관리를 해도 된다.
SMTP_PASSWORD = open('./email_config', 'r').read()
그럴경우 이렇게 파일 읽어오면 됨.
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
필요한 라이브러리들을 import
해준다.
편지를 보내려면 편지봉투가 필요하잔아요?
누구한테, 누가 보내는지, 내용에 뭐가 있는지를 알려주는 파트임당.
# 편지봉투 만들기
msg = MIMEMultipart('alternative')
# 편지 내용
msg['From'] = SMTP_USER
msg['To'] = SMTP_USER
msg['Subject'] = '제목'
contents = "테스트"
# 편지지를 편지봉투에 담아준다
text = MIMEText(contents)
msg.attach(text)
만약에 첨부파일이 있다면
if attachment:
msg = MIMEMultipart('mixed')
alternative
가 아닌 mixed
를 써주면 됩니다!
smtplib
를 import
해주고 다음과 같이 try-except-finally
구문으로 메일 발송 부분을 작성할 수 있다.
import smtplib
try:
# 이메일 전송 서버에 접속
smtp = smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT)
print('메일 서버 접속 성공')
smtp.login(SMTP_USER, SMTP_PASSWORD)
print('로그인 성공!')
smtp.sendmail(from_addrs, to_addrs, msg.as_string())
print('이메일 발송 성공!')
except Exception as e:
# 에러났을 때 실행할 코드
print('#### 에러 발생 ####')
print(e)
finally:
# 에러 여부 상관없이 무조건 실행할 코드
# smtp 연결 해제
smtp.close()
print('Finally')
print
구문들은 제대로 작동하고 있는지 확인하기 위함이다!
만약에 엑세스가 거부된다면
네이버 메일 환경설정
에서 IMAP/SMTP 설정
에서 IMAP/SMTP 사용
을 사용함
으로 바꿔주면 된다.
그 외 오류가 난다면 본인 비밀번호가 틀린 문제거나, 네이버 로그인 2단계 인증을 사용하시는 분일텐데 👉네이버 외부 메일, 2단계 인증 사용자 적용 방법 요기 보시면 도움이 되실듯..
나는 2단계 인증 사용 안해서 메일 설정만 바꿔주니 정상적으로 보내졌다!
from email.mime.base import MIMEBase #'base64'라는 데이터타입을 사용
from email import encoders
from os.path import basename
마찬가지로 필요한 라이브러리들을 import
해주고~
# 파일 담을 공간
email_file = MIMEBase('application', 'octet-stream')
# 파일 읽어오기
with open('실습3/example3.xlsx', 'rb') as f:
file_data = f.read()
# .set_payload로 file_data를 첨부파일에 담아준다.
email_file.set_payload(file_data)
# base64인코딩형식으로 인코딩
encoders.encode_base64(email_file)
file_name = basename('실습3/example3.xlsx')
email_file.add_header('Content-Disposition', 'attachment', filename=file_name)
msg.attach(email_file)
basename
은 파일명만 따오기 위한 것이다. 경로를 적어줘도 example3.xlsx
만 가져옴!
이렇게 작성해주면 된다. 강사님도 이 부분은 못외웠다고 하심. 그러니까 필요할때마다 찾아 쓰면 됨!
이 코드를 실행하고 메일발송 코드를 실행시키면 첨부파일이 예쁘게 담겨져서 온다.
위 코드들을 하나로 합쳐주면 된다.
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
SMTP_SERVER = 'smtp.naver.com'
SMTP_PORT = 465
SMTP_USER = 'email_addrs'
SMTP_PASSWORD = open('./email_config', 'r').read()
def send_mail(addrs, title, content, attachment = False):
msg = MIMEMultipart('alternative')
if attachment:
msg = MIMEMultipart('mixed')
msg['From'] = SMTP_USER
msg['To'] = addrs
msg['Subject'] = title
contents = content
text = MIMEText(contents)
msg.attach(text)
# 첨부파일이 있다면
if attachment:
from email.mime.base import MIMEBase
from email import encoders
from os.path import basename
email_file = MIMEBase('appliacation', 'octet-stream')
with open(attachment, 'rb') as f:
file_data = f.read()
email_file.set_payload(file_data)
encoders.encode_base64(email_file)
file_name = basename(attachment)
email_file.add_header('Content-Disposition', 'attachment', filename=file_name)
msg.attach(email_file)
# 메일 발송
try:
smtp = smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT)
smtp.login(SMTP_USER, SMTP_PASSWORD)
smtp.sendmail(SMTP_USER, addrs, msg.as_string())
except Exception as e:
print('#### 에러 발생 ####')
print(e)
finally:
# smtp 연결 해제
smtp.close()
별거 없죵?
나는 나의 네이버 메일에서 지메일로 보내주기로 했다. 해당 함수를 실행하면
send_mail(my_gmail_addrs, '실습4', '실습4 test')
잘 온다. 첨부파일이 없기때문에 첨부파일은 안왔음.
만약에 첨부파일을 같이 보낸다면
send_mail(my_gmail_addrs, '실습4', '실습4 test', '실습3/example3.xlsx')
attachment
에 파일경로 넣어주면 됨.
역시 잘 왔당 ㅎㅎ
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
from os.path import basename
import smtplib
# 이메일 발송을 위한 상수변수들 설정
SMTP_SERVER = 'smtp.naver.com'
SMTP_PORT = 465
SMTP_USER = email_addres
SMTP_PASSWORD = open('./email_config', 'r').read().rstrip()
# 이메일 발송 함수
def send_mail(from_user:str, to_users:list, subject:str, content:str, attachments:list=[], cc_targets=[]) -> bool:
'''
메일을 발송하는 함수입니다.
**필수값**
from_user: 보내는 사람의 이메일 주소
to_users: 받는 사람의 이메일 주소들 (list)
subject: 메일 제목
content: 메일 내용
**선택**
attachments: 첨부 파일들 (파일경로 리스트)
cc_targets: 참조 이메일 주소들 (list)
'''
try:
# 이메일 전송 서버에 접속
smtp = smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT)
print('메일 전송 서버 접속 성공')
smtp.login(SMTP_USER, SMTP_PASSWORD)
print('로그인 성공 !')
# 편지봉투 만들기
msg = MIMEMultipart('alternative')
# 첨부파일여부
# True : 1, ['result.xlsx'], 'a'
# False : 0, [], ''
if attachments:
msg = MIMEMultipart('mixed')
for attachment in attachments:
# 파일 담을 공간 (첨부 파일)
email_file = MIMEBase('application', 'octet-stream')
# 파일 읽어오기
with open(attachment, 'rb') as f:
file_data = f.read()
# 파일 데이터를 첨부파일에 담아준다.
email_file.set_payload(file_data)
# base64 인코딩형식으로 인코딩
encoders.encode_base64(email_file)
file_name = basename(attachment)
email_file.add_header('Content-Disposition', 'attachment',
filename=file_name)
msg.attach(email_file)
msg['From'] = from_user
msg['To'] = ','.join(to_users)
if cc_targets:
msg['CC'] = ','.join(cc_targets)
msg['Subject'] = subject
# 편지지를 편지봉투에 담아준다.
text = MIMEText(content)
msg.attach(text)
# sendmail('보내는 사람', '받는 사람', msg.as_string())
smtp.sendmail(from_user, ','.join(to_users+cc_targets), msg.as_string())
print('이메일 발송 성공 !')
return True
except Exception as e:
# 에러났을 때 실행할 코드
print('#### 에러 발생 ####')
print(e)
finally:
# 에러 여부 상관없이 무조건 실행할 코드
# smtp 연결 해제
smtp.close()
return False
라이브러리들을 import
하는 경우 함수 밖에 빼주는게 좋다고 하심. 메모✍
강사님은 받는 사람이 여러명일 수도 있으니 그 대상들을 list
로 받고, 첨부파일도 여러개일 수 있으니 list
로 받아주셨다. 또 참조가 있을 수도 있으니 cc_targets
도 parameters
에 넣어주심.
함수 설명에 나와있다시피 첨부파일과 참조이메일 주소들은 필수항목이 아니다.
만약에 이메일 전송 서버에 접속 실패할 수도 있으니 크게 try-except-finally
로 묶어주셨다.
진짜 이메일들이 이런식으로 작동하는 것 아닐까!
smtp.sendmail(from_user, ','.join(to_users+cc_targets), msg.as_string())
join
해주면 맨 앞에 있는 이메일에게만 메일이 전송된다고 한다.smtp.sendmail(from_user, set(to_users+cc_targets), msg.as_string())
iterable
한 객체로 넣어줘야함!!import openpyxl
# def send_mail(addrs, title, content, attachment = False):
xlsx = openpyxl.load_workbook('./실습5/수강생_결제정보.xlsx', read_only = True)
sheet = xlsx.active
for row in sheet.iter_rows():
D_row = row[3].value
if D_row == '결제완료':
send_mail(addrs, '실습5', '실습5 test', './실습5/커리큘럼.xlsx')
openpyxl
로 엑셀 파일 .load_workbook
해주고 위에서 작성한 함수로 메일을 보내주기만 하면 끝
얘는 내 네이버 메일로 전송했다.
결제완료된 수강생이 10명이므로 메일도 10개 다 잘 온 것을 확인할 수 있다!
만약에 해당 엑셀에서 이메일정보까지 불러온다면 엑셀 시트에서 B열이 이메일 정보니까 이 역시 for
문 안에 넣어줘서 B_row = row[1].value
이렇게 해주면 될듯욤?
실습자료의 이메일이 강사님 이메일이라 나는 그냥 내 이메일 주소 넣고 했음.
import openpyxl
from email_manager import send_mail
workbook = openpyxl.load_workbook('./실습5/수강생_결제정보.xlsx', read_only = True)
sheet = workbook.active
target_users = []
for row in sheet.iter_rows(min_row=2):
if row[3].value == '결제완료':
email_address = row[1].value
target_users.append(email_address)
is_send = send_mail(email_addrs, [email_address],
subject='결제완료 안내 메일',
content = '결제완료 되었습니다.',
attachments=['RPA/실습5/커리큘럼.xlsx'])
if is_send:
print('발송완료')
위에 올린 엑셀파일 캡처를 보면 알겠지만 1행은 헤더부분이다. (수강생이름, 이메일, 수강신청일, 결제여부, 결제일) 그래서 2행부터 읽어주면 되는데 이를 sheet.iter_rows(min_row=2)
이렇게 나타내주면 된다. min_row
라는 인자가 있음을 확인하기!
그리고 send_mail
이 for
문 안에 있어도 상관 없지만(받는 사람 메일을 row[1].value
로 두고 계속 갱신해도 됨) 어차피 그 외에는 다 똑같은 내용들이니까 반복문 밖으로 빼주고, 결제완료
인 사람들의 이메일을 target_users
에 list
로 받아서 처리해주는 방법이다.
사실 그렇게 막 로직이 다르고 .. 크게 다를바 없는 코드지만 sheet.iter_rows(min_row=2)
같은 섬세한 부분이 더 좋은 코드를 만들어 내는 것 같다. 뭐.. 결제완료
라는 단어가 헤더에 들어가있진 않지만 혹시 헤더부분과 엑셀시트의 내용이 겹치는 경우가 있으면 곤란해지니까?
오늘 수업은 여기까지였다. 이메일을 처음 다뤄봤는데 너무 신기했음.. 이렇게 메일을 보낼 수 있는 거구나😜 이제 프로젝트..하자..