60 lines
1.9 KiB
Python
60 lines
1.9 KiB
Python
"""SMTP 발송: smtplib STARTTLS + Sent 폴더 자동 저장"""
|
|
import smtplib, ssl, asyncio
|
|
from email.mime.multipart import MIMEMultipart
|
|
from email.mime.text import MIMEText
|
|
from email.mime.base import MIMEBase
|
|
from email import encoders
|
|
from email.utils import formatdate
|
|
from typing import Optional
|
|
|
|
SMTP_HOST = "localhost"
|
|
SMTP_PORT = 587
|
|
|
|
|
|
async def send_mail(
|
|
username: str, password: str,
|
|
to: str, subject: str, body: str,
|
|
cc: Optional[str] = None, bcc: Optional[str] = None,
|
|
is_html: bool = False,
|
|
attachments: Optional[list] = None,
|
|
) -> bytes:
|
|
"""발송 성공 시 raw 메시지 바이트 반환 (Sent 폴더 저장용)"""
|
|
msg = MIMEMultipart("alternative" if is_html else "mixed")
|
|
msg["From"] = username
|
|
msg["To"] = to
|
|
msg["Subject"] = subject
|
|
msg["Date"] = formatdate(localtime=True)
|
|
if cc: msg["Cc"] = cc
|
|
|
|
msg.attach(MIMEText(body, "html" if is_html else "plain", "utf-8"))
|
|
|
|
if attachments:
|
|
for name, data, ctype in attachments:
|
|
part = MIMEBase(*ctype.split("/", 1))
|
|
part.set_payload(data)
|
|
encoders.encode_base64(part)
|
|
part.add_header("Content-Disposition", "attachment", filename=name)
|
|
msg.attach(part)
|
|
|
|
recipients = [r.strip() for r in to.split(",")]
|
|
if cc: recipients += [r.strip() for r in cc.split(",")]
|
|
if bcc: recipients += [r.strip() for r in bcc.split(",")]
|
|
|
|
raw_bytes = msg.as_bytes()
|
|
user_short = username.split("@")[0]
|
|
|
|
def _do():
|
|
ctx = ssl.create_default_context()
|
|
ctx.check_hostname = False
|
|
ctx.verify_mode = ssl.CERT_NONE
|
|
s = smtplib.SMTP(SMTP_HOST, SMTP_PORT, timeout=15)
|
|
s.ehlo()
|
|
s.starttls(context=ctx)
|
|
s.ehlo()
|
|
s.login(user_short, password)
|
|
s.sendmail(username, recipients, raw_bytes)
|
|
s.quit()
|
|
|
|
await asyncio.get_event_loop().run_in_executor(None, _do)
|
|
return raw_bytes
|