sending email async with celery

This commit is contained in:
2025-06-02 14:55:50 +02:00
parent 66ac834ab0
commit c95a1c456b
9 changed files with 195 additions and 49 deletions

View File

@@ -1,14 +1,16 @@
from flask import request
from models import Notif, NotifType, db, EmailTemplate, Mail, KeyValueSettings
from models import Notif, NotifType, db, EmailTemplate, Mail, KeyValueSettings, User
from typing import Optional, Dict, Any, List
from datetime import datetime, timedelta
from flask_login import current_user
from sqlalchemy import desc
from sqlalchemy import desc, and_
import logging
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.utils import formatdate
import json
from celery_worker import celery
logger = logging.getLogger(__name__)
@@ -29,57 +31,65 @@ def get_smtp_settings() -> Optional[Dict[str, Any]]:
logger.error(f"Error retrieving SMTP settings: {str(e)}")
return None
def send_email_via_smtp(mail: Mail) -> bool:
"""
Send an email using the configured SMTP settings.
Args:
mail: The Mail object containing the email details
Returns:
bool: True if email was sent successfully, False otherwise
"""
smtp_settings = get_smtp_settings()
if not smtp_settings:
logger.error("Cannot send email: SMTP settings not configured")
return False
@celery.task
def send_email_task(mail_id: int):
"""Celery task to send an email asynchronously"""
try:
# Get the mail record
mail = Mail.query.get(mail_id)
if not mail:
logger.error(f"Mail record not found for ID: {mail_id}")
return False
# Get SMTP settings
smtp_settings = get_smtp_settings()
if not smtp_settings:
logger.error("SMTP settings not found")
mail.status = 'failed'
mail.error_message = "SMTP settings not found"
db.session.commit()
return False
# Create message
msg = MIMEMultipart()
msg['From'] = f"{smtp_settings['smtp_from_name']} <{smtp_settings['smtp_from_email']}>"
msg['To'] = mail.recipient
msg['From'] = smtp_settings.sender_email
msg['To'] = mail.recipient_email
msg['Subject'] = mail.subject
msg['Date'] = formatdate(localtime=True)
# Attach HTML body
msg.attach(MIMEText(mail.body, 'html'))
# Create SMTP connection
if smtp_settings['smtp_security'] == 'ssl':
server = smtplib.SMTP_SSL(smtp_settings['smtp_host'], int(smtp_settings['smtp_port']))
else:
server = smtplib.SMTP(smtp_settings['smtp_host'], int(smtp_settings['smtp_port']))
if smtp_settings['smtp_security'] == 'tls':
server.starttls()
# Login if credentials are provided
if smtp_settings['smtp_username'] and smtp_settings['smtp_password']:
server.login(smtp_settings['smtp_username'], smtp_settings['smtp_password'])
# Add HTML content
msg.attach(MIMEText(mail.content, 'html'))
# Send email
server.send_message(msg)
server.quit()
with smtplib.SMTP(smtp_settings.smtp_server, smtp_settings.smtp_port) as server:
if smtp_settings.use_tls:
server.starttls()
if smtp_settings.username and smtp_settings.password:
server.login(smtp_settings.username, smtp_settings.password)
server.send_message(msg)
# Update mail status
mail.status = 'sent'
mail.sent_at = datetime.utcnow()
db.session.commit()
logger.info(f"Email sent successfully to {mail.recipient}")
return True
except Exception as e:
logger.error(f"Error sending email: {str(e)}")
if mail:
mail.status = 'failed'
mail.error_message = str(e)
db.session.commit()
return False
def send_email_via_smtp(mail: Mail) -> bool:
"""Queue an email to be sent asynchronously"""
try:
# Queue the email sending task
send_email_task.delay(mail.id)
return True
except Exception as e:
logger.error(f"Error queueing email: {str(e)}")
mail.status = 'failed'
mail.error_message = str(e)
db.session.commit()