diff --git a/src/anonchat/admin_routes.py b/src/anonchat/admin_routes.py
index bcf4d87..da6da64 100644
--- a/src/anonchat/admin_routes.py
+++ b/src/anonchat/admin_routes.py
@@ -2,9 +2,8 @@ from flask import request, render_template, redirect, url_for, flash, session
from functools import wraps
from . import app, db, limiter, csrf
from .models import Inquiry, Message, Settings, Admin
-from .notifiers import webhooks, emails
+from .notifiers import webhooks
from .notifiers.webhooks import WebhookError
-from .notifiers.emails import EmailNotificationError
def is_admin():
return 'admin_authenticated' in session and session['admin_authenticated']
@@ -174,43 +173,4 @@ def admin_settings_webhook():
else:
flash('Webhook settings saved', 'success')
- return redirect(url_for('admin_settings'))
-
-@app.route('/admin/settings/email', methods=['POST'])
-@admin_required
-def admin_settings_email():
- settings = Settings.query.first()
- if not settings:
- settings = Settings()
- db.session.add(settings)
-
- settings.email_notifications_enabled = request.form.get('email_notifications_enabled') == 'on'
- settings.smtp_server = request.form.get('smtp_server', '')
- settings.smtp_use_ssl = request.form.get('smtp_use_ssl') == 'on'
- settings.smtp_username = request.form.get('smtp_username', '')
- settings.smtp_password = request.form.get('smtp_password', '')
- settings.recipient_email = request.form.get('recipient_email', '')
-
- db.session.commit()
-
- if settings.email_notifications_enabled:
- result = emails.verify_email_settings(settings)
- if result['errors']:
- flash(f'Email settings verification failed: {", ".join(result["errors"])}', 'error')
- else:
- try:
- emails.send_email(
- title='Inquiry #1234abcd1234abcd Created',
- inquiry_id='1234abcd1234abcd',
- data={
- 'message': 'This is a test message'
- },
- is_async=False
- )
- flash('Email settings saved and test sent successfully')
- except EmailNotificationError as e:
- flash(f'Email test failed: {str(e)}', 'error')
- else:
- flash('Email notifications svaed', 'success')
-
- return redirect(url_for('admin_settings'))
+ return redirect(url_for('admin_settings'))
\ No newline at end of file
diff --git a/src/anonchat/migrations/add_email_settings.py b/src/anonchat/migrations/add_email_settings.py
deleted file mode 100644
index 8885196..0000000
--- a/src/anonchat/migrations/add_email_settings.py
+++ /dev/null
@@ -1,49 +0,0 @@
-from sqlalchemy import Column, Boolean, String, inspect
-from sqlalchemy.sql import text
-from flask import current_app
-
-def run_migration(db):
- """Add email notification settings columns to the Settings table if they don't exist."""
- current_app.logger.info("Running migration: add_email_settings")
-
- # Check if the table exists first
- inspector = inspect(db.engine)
- if 'settings' not in inspector.get_table_names():
- current_app.logger.info("Settings table doesn't exist yet, skipping migration")
- return False
-
- # Check existing columns
- columns = [col['name'] for col in inspector.get_columns('settings')]
-
- # Track if we need to commit changes
- changes_made = False
-
- # Dictionary of columns to add with their types
- columns_to_add = {
- 'email_notifications_enabled': 'BOOLEAN DEFAULT FALSE',
- 'smtp_server': 'VARCHAR(255)',
- 'smtp_use_ssl': 'BOOLEAN DEFAULT FALSE',
- 'smtp_username': 'VARCHAR(255)',
- 'smtp_password': 'VARCHAR(255)',
- 'recipient_email': 'VARCHAR(255)',
- 'notification_show_message': 'BOOLEAN DEFAULT FALSE',
- 'auto_delete_hours': 'INTEGER DEFAULT 48'
- }
-
- # Add each column if it doesn't exist
- for column_name, column_type in columns_to_add.items():
- if column_name not in columns:
- current_app.logger.info(f"Adding {column_name} column to settings table")
- with db.engine.connect() as conn:
- conn.execute(text(f"ALTER TABLE settings ADD COLUMN {column_name} {column_type}"))
- conn.commit()
- changes_made = True
- else:
- current_app.logger.info(f"{column_name} column already exists in settings table")
-
- if changes_made:
- current_app.logger.info("Migration completed successfully")
- else:
- current_app.logger.info("No changes needed, all columns already exist")
-
- return changes_made
\ No newline at end of file
diff --git a/src/anonchat/models/settings.py b/src/anonchat/models/settings.py
index 45df5fa..f6586fc 100644
--- a/src/anonchat/models/settings.py
+++ b/src/anonchat/models/settings.py
@@ -8,14 +8,6 @@ class Settings(db.Model):
webhook_url = db.Column(db.String(255), nullable=True)
webhook_secret = db.Column(db.String(255), nullable=True)
- # Email notification settings
- email_notifications_enabled = db.Column(db.Boolean, default=False)
- smtp_server = db.Column(db.String(255), nullable=True)
- smtp_use_ssl = db.Column(db.Boolean, default=False)
- smtp_username = db.Column(db.String(255), nullable=True)
- smtp_password = db.Column(db.String(255), nullable=True) # Consider storing this securely
- recipient_email = db.Column(db.String(255), nullable=True)
-
notification_show_message = db.Column(db.Boolean, default=False)
auto_delete_hours = db.Column(db.Integer, default=48)
\ No newline at end of file
diff --git a/src/anonchat/notifiers/__init__.py b/src/anonchat/notifiers/__init__.py
index cf63aae..327427d 100644
--- a/src/anonchat/notifiers/__init__.py
+++ b/src/anonchat/notifiers/__init__.py
@@ -1,7 +1,7 @@
from flask import current_app
-from .emails import send_email
from .webhooks import send_webhook
+
MESSAGE_PREVIEW_LENGTH = 30
EVENT_TYPES = {
'inquiry_created': 'Inquiry #{} Created',
@@ -46,15 +46,6 @@ def inquiry_message(inquiry_id: str, message: str = None, is_async: bool = True)
### Private methods ###
def _send_event(event_type: str, inquiry_id: str, message: str = None, is_async: bool = True) -> None:
- _send_email_ignore_errors(
- title=EVENT_TYPES[event_type].format(inquiry_id),
- inquiry_id=inquiry_id,
- data={
- 'message': _get_message_preview(message) if message else None
- },
- is_async=is_async
- )
-
_send_webhook_ignore_errors(
event_type=event_type,
data={
@@ -64,12 +55,6 @@ def _send_event(event_type: str, inquiry_id: str, message: str = None, is_async:
is_async=is_async
)
-def _send_email_ignore_errors(title, inquiry_id, data, is_async=True):
- try:
- send_email(title, inquiry_id, data, is_async)
- except:
- pass
-
def _send_webhook_ignore_errors(event_type, data, is_async=True):
try:
send_webhook(event_type, data, is_async)
diff --git a/src/anonchat/notifiers/emails.py b/src/anonchat/notifiers/emails.py
deleted file mode 100644
index 9477c13..0000000
--- a/src/anonchat/notifiers/emails.py
+++ /dev/null
@@ -1,156 +0,0 @@
-import smtplib
-from email.message import EmailMessage
-import threading
-from datetime import datetime
-from flask import current_app
-from ..models import Settings
-
-class EmailNotificationError(Exception):
- """Exception raised for errors in the email notification process.
-
- Attributes:
- message -- explanation of the error
- original_exception -- the original exception that caused this error (optional)
- """
-
- def __init__(self, message, original_exception=None):
- self.message = message
- self.original_exception = original_exception
- super().__init__(self.message)
-
-
-def verify_email_settings(settings: Settings = None):
- """
- Verifies that email notification settings are properly configured.
-
- Returns:
- dict: A dictionary containing:
- - 'valid' (bool): Whether settings are valid for sending emails
- - 'errors' (list): List of error messages if any settings are invalid
- - 'settings' (dict): Current settings state (without sensitive values)
- """
-
- if settings is None:
- settings = Settings.query.first()
-
- result = {
- 'valid': False,
- 'errors': [],
- 'settings': {}
- }
-
- # Check if settings exist and notifications are enabled
- if not settings:
- result['errors'].append("Settings not found in database")
- return result
-
- result['settings']['email_notifications_enabled'] = settings.email_notifications_enabled
- if not settings.email_notifications_enabled:
- result['errors'].append("Email notifications are disabled")
- return result
-
- # Required fields
- required_fields = {
- 'smtp_server': settings.smtp_server,
- 'smtp_username': settings.smtp_username,
- 'recipient_email': settings.recipient_email
- }
-
- # Check required fields
- for field, value in required_fields.items():
- result['settings'][field] = value
- if not value:
- result['errors'].append(f"Missing required setting: {field}")
-
- # Test SMTP connection if desired (commented out to avoid actual connection attempts)
- # This could be implemented as a separate function that calls this one first
-
- # Mark as valid if no errors
- result['valid'] = len(result['errors']) == 0
-
- return result
-
-def send_email(title: str, inquiry_id: str, data: dict = {}, is_async=False):
- """Sends an email notification, either synchronously or asynchronously."""
- app = current_app._get_current_object()
-
- if is_async:
- _send_email_async(app, title, inquiry_id, data)
- else:
- _send_email_worker(app, title, inquiry_id, data)
-
-def _send_email_async(app, title: str, inquiry_id: str, data: dict = {}):
- """Queue email to be sent in a background thread"""
- thread = threading.Thread(target=_send_email_worker, args=(app, title, inquiry_id, data))
- thread.daemon = True # Thread will exit when main thread exits
- thread.start()
-
-
-def _send_email_worker(app, title: str, inquiry_id: str, data: dict = {}):
- """Worker function that sends the email notification."""
- try:
- with app.app_context():
- settings = Settings.query.first()
- if not settings or not settings.email_notifications_enabled:
- return False
-
- verification_result = verify_email_settings(settings)
- if not verification_result['valid']:
- raise EmailNotificationError(f"Invalid email settings: {', '.join(verification_result['errors'])}")
-
- # Construct email message
- msg = EmailMessage()
- msg['Subject'] = "[AnonChat] " + title
- msg['From'] = settings.smtp_username
- msg['To'] = settings.recipient_email
-
- content = f"""
- Title: {title}
- Timestamp: {datetime.utcnow().isoformat()} UTC
- Inquiry ID: {inquiry_id}
-
- {data.get('message', '') if settings.notification_show_message else ''}"""
-
- msg.set_content(content)
-
- _send_smtp_message(settings, msg)
- app.logger.info(f"Email notification sent for title: {title}")
- except Exception as e:
- app.logger.error(f"Email error: {e}")
-
- if isinstance(e, EmailNotificationError):
- raise e
-
- raise EmailNotificationError(f"Exception: {e}", original_exception=e)
-
-def _get_smtp_server(smtp_server: str):
- smtp_server_parts = smtp_server.split(':')
- smtp_host = smtp_server_parts[0]
-
- if len(smtp_server_parts) > 1:
- smtp_port = int(smtp_server_parts[1])
- else:
- smtp_port = 0
-
- return (smtp_host, smtp_port)
-
-def _send_smtp_message(settings, msg):
- smtp_server = None
-
- smtp_host, smtp_port = _get_smtp_server(settings.smtp_server)
-
- try:
- if settings.smtp_use_ssl:
- smtp_server = smtplib.SMTP_SSL(smtp_host, smtp_port, timeout=10)
- else:
- smtp_server = smtplib.SMTP(smtp_host, smtp_port, timeout=10)
-
- if settings.smtp_username and settings.smtp_password:
- smtp_server.login(settings.smtp_username, settings.smtp_password)
-
- smtp_server.send_message(msg)
- except smtplib.SMTPException as e:
- raise EmailNotificationError(f"SMTP Error: {e}", original_exception=e)
- finally:
- if smtp_server:
- smtp_server.quit()
\ No newline at end of file
diff --git a/src/anonchat/templates/admin/settings.html b/src/anonchat/templates/admin/settings.html
index 19efac8..22445f7 100644
--- a/src/anonchat/templates/admin/settings.html
+++ b/src/anonchat/templates/admin/settings.html
@@ -45,13 +45,6 @@
This will have no effect on inquiries that are already closed.
-
-
-
-
@@ -84,6 +77,13 @@
+
+
+
+
Configure email settings to receive notifications for new inquiries and responses.
-