103 lines
4.3 KiB
Python
103 lines
4.3 KiB
Python
"""
|
|
Email helper functions for Quizzical Beats
|
|
"""
|
|
import smtplib
|
|
from email.mime.multipart import MIMEMultipart
|
|
from email.mime.text import MIMEText
|
|
from email.mime.base import MIMEBase
|
|
from email import encoders
|
|
from flask import current_app
|
|
|
|
def send_email(recipient, subject, body_text, attachments=None):
|
|
"""
|
|
Sends an email with optional attachments.
|
|
|
|
Args:
|
|
recipient (str): Email address of the recipient
|
|
subject (str): Email subject
|
|
body_text (str): Plain text email body
|
|
attachments (list): Optional list of attachment dictionaries with keys:
|
|
- 'data': The binary data of the attachment
|
|
- 'filename': Filename for the attachment
|
|
- 'mimetype': Mimetype string like 'application/pdf'
|
|
|
|
Returns:
|
|
tuple: (success, message) where success is a boolean and message contains
|
|
details about the result
|
|
"""
|
|
# Get mail configuration from environment variables
|
|
mail_host = current_app.config.get('MAIL_HOST')
|
|
mail_port = current_app.config.get('MAIL_PORT')
|
|
mail_username = current_app.config.get('MAIL_USERNAME')
|
|
mail_password = current_app.config.get('MAIL_PASSWORD')
|
|
mail_sender = current_app.config.get('MAIL_SENDER')
|
|
|
|
# Check if all email configuration parameters are available
|
|
missing_config = []
|
|
if not mail_host:
|
|
missing_config.append("MAIL_HOST")
|
|
if not mail_port:
|
|
missing_config.append("MAIL_PORT")
|
|
if not mail_username:
|
|
missing_config.append("MAIL_USERNAME")
|
|
if not mail_password:
|
|
missing_config.append("MAIL_PASSWORD")
|
|
if not mail_sender:
|
|
missing_config.append("MAIL_SENDER")
|
|
|
|
if missing_config:
|
|
missing_params = ", ".join(missing_config)
|
|
error_msg = f"Email server configuration is incomplete. Missing parameters: {missing_params}."
|
|
current_app.logger.error(f"Email configuration error: {error_msg}")
|
|
current_app.logger.error(f"Current config values - MAIL_HOST: {'set' if mail_host else 'missing'}, "
|
|
f"MAIL_PORT: {'set' if mail_port else 'missing'}, "
|
|
f"MAIL_USERNAME: {'set' if mail_username else 'missing'}, "
|
|
f"MAIL_PASSWORD: {'set' if mail_password else 'missing'}, "
|
|
f"MAIL_SENDER: {'set' if mail_sender else 'missing'}")
|
|
return False, error_msg
|
|
|
|
# Create message object
|
|
msg = MIMEMultipart()
|
|
msg['From'] = mail_sender
|
|
msg['To'] = recipient
|
|
msg['Subject'] = subject
|
|
|
|
# Attach text body
|
|
msg.attach(MIMEText(body_text, 'plain'))
|
|
|
|
# Attach files if provided
|
|
if attachments:
|
|
for attachment in attachments:
|
|
part = MIMEBase(
|
|
attachment.get('mimetype', 'application/octet-stream').split('/')[0],
|
|
attachment.get('mimetype', 'application/octet-stream').split('/')[1]
|
|
)
|
|
part.set_payload(attachment['data'])
|
|
encoders.encode_base64(part)
|
|
part.add_header(
|
|
'Content-Disposition',
|
|
f'attachment; filename={attachment["filename"]}'
|
|
)
|
|
msg.attach(part)
|
|
|
|
try:
|
|
current_app.logger.info(f"Attempting to send email to {recipient} via {mail_host}:{mail_port}")
|
|
with smtplib.SMTP(mail_host, mail_port) as server:
|
|
server.starttls()
|
|
current_app.logger.debug("STARTTLS established")
|
|
server.login(mail_username, mail_password)
|
|
current_app.logger.debug(f"Login successful for {mail_username}")
|
|
server.sendmail(mail_sender, recipient, msg.as_string())
|
|
current_app.logger.info(f"Email sent successfully from {mail_sender} to {recipient}")
|
|
|
|
return True, f'Email sent successfully to {recipient}!'
|
|
|
|
except smtplib.SMTPException as e:
|
|
error_msg = str(e)
|
|
current_app.logger.error(f"SMTP Error: {error_msg}")
|
|
current_app.logger.error(f"Failed to send email from {mail_sender} to {recipient} via {mail_host}:{mail_port}")
|
|
return False, error_msg
|
|
except Exception as e:
|
|
error_msg = f"Unexpected error: {str(e)}"
|
|
current_app.logger.error(error_msg)
|
|
return False, error_msg |