"""BAN YARO — Outreach E-Mail (Admin)""" import os import smtplib import ssl from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from email.utils import formataddr from datetime import datetime from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel from typing import List, Optional from auth import require_admin from database import db router = APIRouter() _SMTP_HOST = os.getenv("SMTP_HOST", "") _SMTP_PORT = int(os.getenv("SMTP_PORT", "587")) _SMTP_USER = os.getenv("SMTP_USER", "") _SMTP_PASS = os.getenv("SMTP_PASS", "") _SMTP_FROM = os.getenv("SMTP_FROM", "partner@banyaro.app") TEMPLATES = { "influencer_de": { "label": "Influencer-Ansprache (DE)", "subject": "Ban Yaro — 100 Gründer-Plätze, einer davon für deine Community", "body": """Hallo {name}, ich bin René und habe Ban Yaro gebaut — eine Hunde-App für Tagebuch, Gesundheit, Giftköder-Alarm und Community. Kostenlos, ohne App Store, direkt als PWA. Ich kontaktiere gerade einige Influencer aus der deutschen Hunde-Community mit einem konkreten Angebot: Was deine Follower bekommen: Wer sich mit deinem persönlichen Code registriert, sichert sich einen der 100 Gründer-Plätze — eine nummerierte Badge ("Gründer #42") die dauerhaft im Profil sichtbar ist. Diese 100 Plätze gibt es genau einmal. Was du bekommst: Partner-Badge in der App, eigener Code, öffentliches Ranking wer die meisten Gründer bringt. Kein Geld, kein verpflichtender Post — aber eine echte Exklusivität die du deiner Community geben kannst. Alle Infos: https://banyaro.app/partner Wenn dich das interessiert, antworte einfach kurz — ich richte deinen Code binnen 24h ein. Viele Grüße, René banyaro.app""", }, } class SendRequest(BaseModel): to: List[str] subject: str body: str template_name: Optional[str] = None def _send_smtp(to: str, subject: str, body: str): if not _SMTP_HOST or not _SMTP_USER: raise RuntimeError("SMTP nicht konfiguriert.") msg = MIMEMultipart("alternative") msg["Subject"] = subject msg["From"] = formataddr(("Ban Yaro Partner", _SMTP_FROM)) msg["To"] = to msg["Reply-To"] = _SMTP_FROM msg.attach(MIMEText(body, "plain", "utf-8")) ctx = ssl.create_default_context() with smtplib.SMTP(_SMTP_HOST, _SMTP_PORT, timeout=15) as s: s.ehlo() s.starttls(context=ctx) s.login(_SMTP_USER, _SMTP_PASS) s.sendmail(_SMTP_FROM, to, msg.as_bytes()) @router.get("/templates") def list_templates(user=Depends(require_admin)): return [{"id": k, "label": v["label"], "subject": v["subject"], "body": v["body"]} for k, v in TEMPLATES.items()] @router.post("/send") def send_outreach(data: SendRequest, user=Depends(require_admin)): if not data.to: raise HTTPException(400, "Mindestens eine Empfänger-Adresse angeben.") if not data.subject.strip() or not data.body.strip(): raise HTTPException(400, "Betreff und Text dürfen nicht leer sein.") sent, failed = [], [] for addr in data.to: addr = addr.strip() if not addr: continue try: _send_smtp(addr, data.subject, data.body) sent.append(addr) # Log in DB with db() as conn: conn.execute( """INSERT INTO outreach_log (sent_by, recipient, subject, body, sent_at) VALUES (?, ?, ?, ?, ?)""", (user["id"], addr, data.subject, data.body, datetime.utcnow().isoformat()) ) except Exception as e: failed.append({"addr": addr, "error": str(e)}) return {"sent": sent, "failed": failed} @router.get("/log") def outreach_log(user=Depends(require_admin)): with db() as conn: rows = conn.execute( """SELECT ol.id, ol.recipient, ol.subject, ol.sent_at, u.name AS sent_by_name FROM outreach_log ol JOIN users u ON u.id = ol.sent_by ORDER BY ol.sent_at DESC LIMIT 100""" ).fetchall() return [dict(r) for r in rows]