mirror of
https://github.com/mskatoni/ni-mail.git
synced 2026-09-05 23:47:36 +08:00
feat: complete ni-mail rewrite with Graph API, IMAP, OTP extractor, Web UI and Docker deployment
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
from flask import Blueprint, jsonify, request
|
||||
from app.db import db
|
||||
from app.models import Account
|
||||
|
||||
bp = Blueprint("accounts", __name__, url_prefix="/api/accounts")
|
||||
|
||||
@bp.get("/")
|
||||
def list_accounts():
|
||||
accounts = Account.query.all()
|
||||
return jsonify([a.to_dict() for a in accounts])
|
||||
|
||||
@bp.post("/")
|
||||
def add_account():
|
||||
data = request.json or {}
|
||||
email = data.get("email")
|
||||
if not email:
|
||||
return jsonify({"error": "email is required"}), 400
|
||||
|
||||
acct = Account.query.filter_by(email=email).first()
|
||||
if not acct:
|
||||
acct = Account(email=email)
|
||||
|
||||
acct.method = data.get("method", "graph")
|
||||
acct.client_id = data.get("client_id")
|
||||
acct.refresh_token = data.get("refresh_token")
|
||||
acct.password = data.get("password")
|
||||
|
||||
db.session.add(acct)
|
||||
db.session.commit()
|
||||
return jsonify(acct.to_dict()), 201
|
||||
|
||||
@bp.delete("/<int:acct_id>")
|
||||
def delete_account(acct_id):
|
||||
acct = Account.query.get_or_404(acct_id)
|
||||
db.session.delete(acct)
|
||||
db.session.commit()
|
||||
return jsonify({"success": True})
|
||||
@@ -0,0 +1,53 @@
|
||||
from flask import Blueprint, jsonify, request
|
||||
from app.models import Account
|
||||
from app.services import graph, imap, verification
|
||||
import os
|
||||
|
||||
bp = Blueprint("emails", __name__, url_prefix="/api/emails")
|
||||
|
||||
@bp.get("/")
|
||||
def get_emails():
|
||||
email = request.args.get("email")
|
||||
if not email:
|
||||
return jsonify({"error": "email query param required"}), 400
|
||||
|
||||
acct = Account.query.filter_by(email=email).first()
|
||||
if not acct:
|
||||
return jsonify({"error": "account not found"}), 404
|
||||
|
||||
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:
|
||||
# Fallback to IMAP
|
||||
messages = imap.fetch_inbox_messages(
|
||||
email=acct.email,
|
||||
password=acct.password or acct.refresh_token,
|
||||
limit=15,
|
||||
proxy_url=proxy_url
|
||||
)
|
||||
|
||||
results = []
|
||||
for msg in messages:
|
||||
body = msg.get("body", {}).get("content", "") or msg.get("body_text", "") or ""
|
||||
code, link = verification.extract_code_and_link(body)
|
||||
results.append({
|
||||
"id": msg.get("id"),
|
||||
"subject": msg.get("subject"),
|
||||
"from": msg.get("from", {}).get("emailAddress", {}).get("address", ""),
|
||||
"received_at": msg.get("receivedDateTime"),
|
||||
"otp_code": code,
|
||||
"link": link,
|
||||
"body_preview": body[:300]
|
||||
})
|
||||
|
||||
return jsonify(results)
|
||||
Reference in New Issue
Block a user