Files
SneakyMon/app/main.py

125 lines
3.6 KiB
Python

#!/usr/bin/env python3
"""
Mailpit → Gotify bridge webhook.
Receives POSTs from Mailpit (MP_WEBHOOK_URL) when new mail arrives.
Fetches the full message from the Mailpit API, extracts useful info,
and forwards a summary to Gotify.
"""
import logging
import os
import json
from typing import Any, Dict
import requests
from dotenv import load_dotenv
from flask import Flask, jsonify, request
# ------------------------------------------------------------------ #
# Config & logging
# ------------------------------------------------------------------ #
load_dotenv()
MAILPIT_API = os.getenv("MAILPIT_API", "http://localhost:8025")
MAILPIT_TOKEN = os.getenv("MAILPIT_TOKEN", "")
GOTIFY_URL = os.getenv("GOTIFY_URL","")
GOTIFY_TOKEN = os.getenv("GOTIFY_TOKEN","")
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO").upper()
logging.basicConfig(
level=getattr(logging, LOG_LEVEL, logging.INFO),
format="%(asctime)s [%(levelname)s] %(message)s",
)
log = logging.getLogger("mailpit-hook")
app = Flask(__name__)
from utils.gotify_api import GotifyNotifier
# ------------------------------------------------------------------ #
# Helpers
# ------------------------------------------------------------------ #
def get_mailpit_message(message_id: str) -> Dict[str, Any]:
"""Retrieve full message JSON from Mailpit REST API."""
url = f"{MAILPIT_API}/api/v1/message/{message_id}"
headers = {}
if MAILPIT_TOKEN:
headers["Authorization"] = f"Bearer {MAILPIT_TOKEN}"
resp = requests.get(url, headers=headers, timeout=10)
resp.raise_for_status()
return resp.json()
def send_gotify(title: str, message: str, priority: int = 5) -> None:
"""Send a message to Gotify."""
notify = GotifyNotifier(GOTIFY_URL, GOTIFY_TOKEN)
result = notify.gotify(title=title,markdown=message,priority=5)
if not result:
log.warning("Gotify push failed")
else:
log.info("Gotify push OK")
# ------------------------------------------------------------------ #
# Webhook route
# ------------------------------------------------------------------ #
@app.route("/hook", methods=["POST"])
def hook():
"""
Mailpit sends JSON like:
{
"ID": "abcdef123",
"MessageID": "<...>",
"From": "camera@reolink.local",
"Subject": "Motion Detected",
...
}
"""
data = request.get_json(silent=True) or {}
mail_msg_id = data.get("MessageID")
msg_id = data.get("ID")
if not msg_id:
log.warning("Webhook received malformed payload: %s", data)
return jsonify({"error": "missing ID"}), 400
log.info(f"Webhook triggered for message ID={msg_id} - Email MSG_ID={mail_msg_id}")
result = handle_hook(msg_id)
if result:
return jsonify({"status": "ok"}), 200
else:
return jsonify({"error":"Error sending webhook"}), 500
def handle_hook(msg_id:str):
try:
msg = get_mailpit_message(msg_id)
subject = msg.get("Subject", "(no subject)")
text = msg.get("Text", "") or msg.get("HTML", "")
preview = (text or "")
if len(preview) > 200:
preview = preview[:200] + "..."
send_gotify(subject, preview)
return True
except Exception as e:
log.exception("Error processing webhook: %s", e)
return False
# ------------------------------------------------------------------ #
# Entry point
# ------------------------------------------------------------------ #
if __name__ == "__main__":
# msg_id = "ZTUUK57e7kUoaviua6TCgP@mailpit"
# msg = get_mailpit_message(msg_id)
app.run(host="0.0.0.0", port=8088)