diff --git a/app/__init__.py b/app/__init__.py index 8fe9131..5bc1f46 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,16 +1,22 @@ -__version__ = "1.1.0" import os from flask import Flask, render_template, jsonify +from dotenv import load_dotenv from app.db import db from app.api import accounts, emails +__version__ = "1.1.0" + def create_app(): + load_dotenv() app = Flask(__name__) - db_path = os.getenv("DATABASE_URL", f"sqlite:///{os.path.join(os.getcwd(), 'ni_mail.db')}") + data_dir = os.getenv("DATA_DIR", os.getcwd()) + default_db = f"sqlite:///{os.path.join(data_dir, 'ni_mail.db')}" + db_path = os.getenv("DATABASE_URL", default_db) + app.config["SQLALCHEMY_DATABASE_URI"] = db_path app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False - app.config["SECRET_KEY"] = os.getenv("SECRET_KEY", "ni-mail-secret-key") + app.config["SECRET_KEY"] = os.getenv("SECRET_KEY", "ni-mail-secret-key-v1.1.0") db.init_app(app) @@ -23,7 +29,11 @@ def create_app(): @app.route("/health") def health(): - return jsonify({"status": "ok", "app": "ni-mail"}) + return jsonify({ + "status": "ok", + "app": "ni-mail", + "version": __version__ + }) with app.app_context(): db.create_all() diff --git a/app/api/emails.py b/app/api/emails.py index b1cf42d..4c5337b 100644 --- a/app/api/emails.py +++ b/app/api/emails.py @@ -18,22 +18,27 @@ def get_emails(): proxy_url = os.getenv("PROXY_URL") messages = [] - if acct.method == "graph": - token_res = graph.get_access_token_graph_result( - client_id=acct.client_id, - refresh_token=acct.refresh_token, - proxy_url=proxy_url - ) - if isinstance(token_res, dict) and "access_token" in token_res: - token = token_res["access_token"] - messages = graph.fetch_messages(token, top=15, proxy_url=proxy_url) - else: - messages = imap.fetch_inbox_messages( - email=acct.email, - password=acct.password or acct.refresh_token, - limit=15, - proxy_url=proxy_url - ) + try: + if acct.method == "graph": + token_res = graph.get_access_token_graph_result( + client_id=acct.client_id, + refresh_token=acct.refresh_token, + proxy_url=proxy_url + ) + if isinstance(token_res, dict) and "access_token" in token_res: + token = token_res["access_token"] + messages = graph.fetch_messages(token, top=15, proxy_url=proxy_url) + elif isinstance(token_res, dict) and "error" in token_res: + return jsonify({"error": token_res["error"]}), 400 + else: + messages = imap.fetch_inbox_messages( + email=acct.email, + password=acct.password or acct.refresh_token, + limit=15, + proxy_url=proxy_url + ) + except Exception as e: + return jsonify({"error": f"Failed to fetch emails: {str(e)}"}), 500 results = [] for msg in messages: @@ -42,7 +47,7 @@ def get_emails(): results.append({ "id": msg.get("id"), "subject": msg.get("subject"), - "from": msg.get("from", {}).get("emailAddress", {}).get("address", ""), + "from": msg.get("from", {}).get("emailAddress", {}).get("address", "") if isinstance(msg.get("from"), dict) else str(msg.get("from", "")), "received_at": msg.get("receivedDateTime"), "otp_code": code, "link": link, @@ -68,21 +73,21 @@ def send_email(): proxy_url = os.getenv("PROXY_URL") - if acct.method == "graph": - token_res = graph.get_access_token_graph_result( - client_id=acct.client_id, - refresh_token=acct.refresh_token, - proxy_url=proxy_url - ) - if isinstance(token_res, dict) and "access_token" in token_res: - token = token_res["access_token"] - success = graph.send_mail_graph(token, to_email, subject, body, proxy_url=proxy_url) - if success: - return jsonify({"success": True, "message": "Email sent via Graph API"}) - return jsonify({"error": "Graph API send mail failed"}), 500 - return jsonify({"error": "Token refresh failed"}), 400 - else: - try: + try: + if acct.method == "graph": + token_res = graph.get_access_token_graph_result( + client_id=acct.client_id, + refresh_token=acct.refresh_token, + proxy_url=proxy_url + ) + if isinstance(token_res, dict) and "access_token" in token_res: + token = token_res["access_token"] + success = graph.send_mail_graph(token, to_email, subject, body, proxy_url=proxy_url) + if success: + return jsonify({"success": True, "message": "Email sent via Graph API"}) + return jsonify({"error": "Graph API send mail failed"}), 500 + return jsonify({"error": "Token refresh failed"}), 400 + else: success = smtp.send_mail_smtp( host=os.getenv("SMTP_HOST", "smtp.office365.com"), port=int(os.getenv("SMTP_PORT", "587")), @@ -95,7 +100,6 @@ def send_email(): ) if success: return jsonify({"success": True, "message": "Email sent via SMTP"}) - except Exception as e: - return jsonify({"error": f"SMTP send mail failed: {str(e)}"}), 500 - - return jsonify({"error": "Send mail failed"}), 500 + return jsonify({"error": "SMTP send mail failed"}), 500 + except Exception as e: + return jsonify({"error": f"Send mail failed: {str(e)}"}), 500 diff --git a/app/services/graph.py b/app/services/graph.py index 9b74e7c..daf0c2f 100644 --- a/app/services/graph.py +++ b/app/services/graph.py @@ -1,4 +1,5 @@ from __future__ import annotations +from app.services.http import build_error_payload, get_response_details from typing import Any, Dict, List, Optional diff --git a/app/services/http.py b/app/services/http.py index 8b80316..a21cbcf 100644 --- a/app/services/http.py +++ b/app/services/http.py @@ -1,12 +1,16 @@ -from __future__ import annotations +from typing import Any, Dict -from typing import Any - -import requests - - -def get_response_details(response: requests.Response) -> Any: +def get_response_details(res) -> str: try: - return response.json() + return res.text[:500] except Exception: - return response.text or response.reason + return "No response details" + +def build_error_payload(code: str, message: str, error_type: str = "APIError", status_code: int = 500, details: Any = None) -> Dict[str, Any]: + return { + "code": code, + "message": message, + "type": error_type, + "status": status_code, + "details": details + } diff --git a/app/services/imap.py b/app/services/imap.py index b4ccfa9..81bf42c 100644 --- a/app/services/imap.py +++ b/app/services/imap.py @@ -1,4 +1,5 @@ from __future__ import annotations +from app.services.http import build_error_payload, get_response_details import email import hashlib