Files
tp-ems/backend/app/services/email_service.py
Du Wenbo d8e4449f10 Squashed 'core/' content from commit 92ec910
git-subtree-dir: core
git-subtree-split: 92ec910a132e379a3a6e442a75bcb07cac0f0010
2026-04-04 18:16:49 +08:00

106 lines
3.4 KiB
Python

"""邮件发送服务 - SMTP email sending for alarm notifications and report delivery."""
import logging
import smtplib
import ssl
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
from pathlib import Path
from typing import Optional
from app.core.config import get_settings
logger = logging.getLogger("email_service")
async def send_email(
to: list[str],
subject: str,
body_html: str,
attachments: Optional[list[str]] = None,
) -> bool:
"""
Send an email via SMTP.
Args:
to: List of recipient email addresses.
subject: Email subject line.
body_html: HTML body content.
attachments: Optional list of file paths to attach.
Returns:
True if sent successfully, False otherwise.
"""
settings = get_settings()
if not settings.SMTP_ENABLED:
logger.warning("SMTP is not enabled (SMTP_ENABLED=False). Skipping email send.")
return False
if not settings.SMTP_HOST:
logger.warning("SMTP_HOST is not configured. Skipping email send.")
return False
if not to:
logger.warning("No recipients specified. Skipping email send.")
return False
try:
msg = MIMEMultipart("mixed")
msg["From"] = settings.SMTP_FROM
msg["To"] = ", ".join(to)
msg["Subject"] = subject
# HTML body
html_part = MIMEText(body_html, "html", "utf-8")
msg.attach(html_part)
# Attachments
if attachments:
for filepath in attachments:
path = Path(filepath)
if not path.exists():
logger.warning(f"Attachment not found, skipping: {filepath}")
continue
with open(path, "rb") as f:
part = MIMEBase("application", "octet-stream")
part.set_payload(f.read())
encoders.encode_base64(part)
part.add_header(
"Content-Disposition",
f'attachment; filename="{path.name}"',
)
msg.attach(part)
# Send via SMTP
context = ssl.create_default_context()
if settings.SMTP_PORT == 465:
# SSL connection
with smtplib.SMTP_SSL(settings.SMTP_HOST, settings.SMTP_PORT, context=context) as server:
if settings.SMTP_USER and settings.SMTP_PASSWORD:
server.login(settings.SMTP_USER, settings.SMTP_PASSWORD)
server.sendmail(settings.SMTP_FROM, to, msg.as_string())
else:
# STARTTLS connection (port 587 or 25)
with smtplib.SMTP(settings.SMTP_HOST, settings.SMTP_PORT) as server:
server.ehlo()
if settings.SMTP_PORT == 587:
server.starttls(context=context)
server.ehlo()
if settings.SMTP_USER and settings.SMTP_PASSWORD:
server.login(settings.SMTP_USER, settings.SMTP_PASSWORD)
server.sendmail(settings.SMTP_FROM, to, msg.as_string())
logger.info(f"Email sent successfully to {to}, subject: {subject}")
return True
except smtplib.SMTPException as e:
logger.error(f"SMTP error sending email to {to}: {e}")
return False
except Exception as e:
logger.error(f"Unexpected error sending email to {to}: {e}")
return False