Spaces:
Sleeping
Sleeping
from flask import Flask, request, jsonify | |
from flask_cors import CORS | |
import smtplib | |
from email.mime.multipart import MIMEMultipart | |
from email.mime.text import MIMEText | |
# from email.mime.base import MIMEBase # Not used in simplified version | |
# from email import encoders # Not used in simplified version | |
import base64 | |
import os | |
import socket | |
import traceback | |
# <<<--- FLASK APP INITIALIZATION MUST BE HERE (TOP LEVEL) --->>> | |
app = Flask(__name__) | |
CORS(app) | |
# <<<--------------------------------------------------------->>> | |
# Environment variables will be set as Secrets in Hugging Face Space settings | |
SMTP_SERVER_HOST = os.environ.get("SMTP_SERVER_HOST") | |
SMTP_SERVER_PORT = os.environ.get("SMTP_SERVER_PORT") | |
SMTP_SENDER_EMAIL = os.environ.get("SMTP_SENDER_EMAIL") | |
SMTP_SENDER_PASSWORD = os.environ.get("SMTP_SENDER_PASSWORD") | |
SMTP_CONNECTION_TIMEOUT = 30 | |
SMTP_COMMAND_TIMEOUT = 30 | |
# This decorator now correctly sees 'app' | |
def handle_send_email(): | |
request_id = base64.b64encode(os.urandom(6)).decode('utf-8') | |
print(f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - Received request at /send-report-via-email") | |
if not all([SMTP_SERVER_HOST, SMTP_SERVER_PORT, SMTP_SENDER_EMAIL, SMTP_SENDER_PASSWORD]): | |
error_msg = "EMAIL_SENDER_API (HF) [{request_id}]: ERROR - SMTP environment variables (Secrets) not fully set." | |
print(error_msg) | |
return jsonify({"status": "error", "message": "Email server configuration incomplete on the API."}), 500 | |
try: | |
SMTP_PORT_INT = int(SMTP_SERVER_PORT) | |
except ValueError: | |
error_msg = f"EMAIL_SENDER_API (HF) [{request_id}]: ERROR - Invalid SMTP_SERVER_PORT: '{SMTP_SERVER_PORT}'." | |
print(error_msg) | |
return jsonify({"status": "error", "message": "Invalid email server port configured on the API."}), 500 | |
data = request.json | |
if not data: | |
print(f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - No JSON data received.") | |
return jsonify({"status": "error", "message": "No data received by email API."}), 400 | |
recipient_email = data.get('recipient_email') | |
# pdf_base64_data = data.get('pdf_base64_data') # Not using these in simplified test | |
# pdf_filename = data.get('pdf_filename') # Not using these in simplified test | |
print(f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - Attempting to send to: {recipient_email}") | |
if not recipient_email: | |
print(f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - Missing recipient_email in JSON payload.") | |
return jsonify({"status": "error", "message": "Missing required data: recipient_email."}), 400 | |
try: | |
# Create a simple plain text message | |
simple_msg = MIMEMultipart() | |
simple_msg['From'] = SMTP_SENDER_EMAIL | |
simple_msg['To'] = recipient_email | |
simple_msg['Subject'] = "EPIC-AMP - Simple Connectivity Test" | |
simple_body = f"Hello {recipient_email},\n\nThis is a simple plain text email to test SMTP connectivity from the EPIC-AMP Hugging Face Space.\n\nIf you receive this, basic SMTP connection, authentication, and sending are working.\n\nRegards,\nThe EPIC-AMP Test System" | |
simple_msg.attach(MIMEText(simple_body, 'plain')) | |
print(f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - Preparing to connect to SMTP server {SMTP_SERVER_HOST}:{SMTP_PORT_INT} with timeout {SMTP_CONNECTION_TIMEOUT}s") | |
server = None | |
try: | |
if SMTP_PORT_INT == 465: # SSL | |
print(f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - Using SMTP_SSL for port 465.") | |
server = smtplib.SMTP_SSL(SMTP_SERVER_HOST, SMTP_PORT_INT, timeout=SMTP_CONNECTION_TIMEOUT) | |
else: # Standard port, try STARTTLS (e.g., for 587) | |
print(f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - Using standard SMTP for port {SMTP_PORT_INT}.") | |
server = smtplib.SMTP(SMTP_SERVER_HOST, SMTP_PORT_INT, timeout=SMTP_CONNECTION_TIMEOUT) | |
server.set_debuglevel(1) | |
print(f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - Connected. Sending EHLO/HELO...") | |
server.ehlo() | |
if SMTP_PORT_INT == 587: | |
print(f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - Port is 587, attempting STARTTLS...") | |
server.starttls() | |
print(f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - STARTTLS successful. Re-sending EHLO...") | |
server.ehlo() | |
print(f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - Attempting login with user: {SMTP_SENDER_EMAIL}...") | |
server.login(SMTP_SENDER_EMAIL, SMTP_SENDER_PASSWORD) | |
print(f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - Login successful. Sending mail to {recipient_email}...") | |
server.sendmail(SMTP_SENDER_EMAIL, recipient_email, simple_msg.as_string()) | |
print(f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - Mail sent successfully.") | |
finally: | |
if server: | |
try: | |
print(f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - Quitting SMTP server connection.") | |
server.quit() | |
except Exception as e_quit: | |
print(f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - Error during server.quit(): {e_quit}") | |
success_msg = f"SIMPLE TEST: Email successfully sent to {recipient_email}." | |
print(f"EMAIL_SENDER_API (HF) [{request_id}]: {success_msg}") | |
return jsonify({"status": "success", "message": success_msg}), 200 | |
# Keep all the specific exception handling blocks | |
except smtplib.SMTPConnectError as e: | |
error_msg = f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - SMTP Connect Error. {e}" | |
print(error_msg); traceback.print_exc() | |
return jsonify({"status": "error", "message": f"SIMPLIFIED TEST - Could not connect: {e.strerror if hasattr(e, 'strerror') else e}"}), 503 | |
except smtplib.SMTPHeloError as e: | |
error_msg = f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - SMTP Helo/Ehlo Error. {e}" | |
print(error_msg); traceback.print_exc() | |
return jsonify({"status": "error", "message": "SIMPLIFIED TEST - Server HELO/EHLO error."}), 502 | |
except smtplib.SMTPAuthenticationError as e: | |
error_msg = f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - SMTP Authentication Error. {e}" | |
print(error_msg); traceback.print_exc() | |
return jsonify({"status": "error", "message": "SIMPLIFIED TEST - Email server authentication failed."}), 500 | |
except socket.timeout as e: | |
error_msg = f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - Socket Timeout. {e}" | |
print(error_msg); traceback.print_exc() | |
return jsonify({"status": "error", "message": "SIMPLIFIED TEST - Connection timed out."}), 504 | |
except socket.gaierror as e: | |
error_msg = f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - Address-related error. {e}" | |
print(error_msg); traceback.print_exc() | |
return jsonify({"status": "error", "message": "SIMPLIFIED TEST - Could not resolve hostname."}), 503 | |
except OSError as e: | |
if e.errno == 101: | |
error_msg = f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - OSError [Errno 101] Network is unreachable. {e}" | |
print(error_msg); traceback.print_exc() | |
return jsonify({"status": "error", "message": "SIMPLIFIED TEST - Network is unreachable from API server."}), 503 | |
else: | |
error_msg = f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - An OS error occurred: {e}" | |
print(error_msg); traceback.print_exc() | |
return jsonify({"status": "error", "message": f"SIMPLIFIED TEST - OS Error: {type(e).__name__}"}), 500 | |
except Exception as e: | |
error_msg = f"EMAIL_SENDER_API (HF) [{request_id}]: SIMPLIFIED TEST - An unexpected error: {e}" | |
print(error_msg) | |
traceback.print_exc() | |
return jsonify({"status": "error", "message": f"SIMPLIFIED TEST - Unexpected API error: {type(e).__name__}"}), 500 | |
# The if __name__ == '__main__': block for local testing: | |
# On Hugging Face Spaces with Gunicorn, Gunicorn directly imports and runs the 'app' object, | |
# so this block isn't strictly executed by Gunicorn. | |
# It's useful if you want to run this script directly with `python email_sender_api.py` for local testing. | |
# if __name__ == '__main__': | |
# # For local testing, set your ENV VARS in this terminal session before running | |
# api_port = int(os.environ.get("PORT", 5002)) # Default to 5002 for local test | |
# print(f"Starting Email Sender API Service locally on port {api_port}...") | |
# # ... (rest of the local startup print messages and app.run) ... | |
# app.run(host='0.0.0.0', port=api_port, debug=True) |