79 lines
2.6 KiB
Python
79 lines
2.6 KiB
Python
# app/routers/mail.py
|
|
from __future__ import annotations
|
|
import base64
|
|
from uuid import UUID
|
|
from fastapi import APIRouter, UploadFile, File, Form, Depends, status, HTTPException
|
|
from fastapi.encoders import jsonable_encoder
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from app.db import get_session
|
|
from app.schemas import SendTestMailRequest, UploadMailResponse
|
|
from app.schema_utils import job_to_schema
|
|
from app.task_enqueue import enqueue_job_with_single_task
|
|
from app.services import create_job, get_job_with_tasks
|
|
from app.job_registry import routing_key
|
|
from email import policy
|
|
from email.parser import BytesParser
|
|
|
|
router = APIRouter(prefix="/api/v1/mail", tags=["mail"])
|
|
|
|
# TODO: vorhandene Auth-Dependency einhängen
|
|
async def api_key_auth():
|
|
return True
|
|
|
|
def _guess_domain_from_addresses(addresses: str | None) -> str:
|
|
if not addresses:
|
|
return "unknown.local"
|
|
# nimmt erste Adresse, extrahiert Domain
|
|
first = addresses.split(",")[0].strip()
|
|
if "@" in first:
|
|
return first.split("@")[-1].strip().lower()
|
|
return "unknown.local"
|
|
|
|
@router.post("/send", status_code=status.HTTP_202_ACCEPTED)
|
|
async def send_test_mail(
|
|
req: SendTestMailRequest,
|
|
_=Depends(api_key_auth),
|
|
session: AsyncSession = Depends(get_session),
|
|
):
|
|
if not req.recipients:
|
|
raise HTTPException(status_code=400, detail="At least one recipient required.")
|
|
domain = req.recipients[0].split("@")[-1].lower()
|
|
job = await create_job(
|
|
session,
|
|
job_type="MailSend",
|
|
domain=domain,
|
|
payload=req.model_dump(mode="json")
|
|
)
|
|
job = await get_job_with_tasks(session, job.id)
|
|
return job_to_schema(job)
|
|
|
|
@router.post("/upload", response_model=UploadMailResponse, status_code=status.HTTP_202_ACCEPTED)
|
|
async def upload_mail(
|
|
mailbox_id: UUID = Form(...),
|
|
eml: UploadFile = File(...),
|
|
_=Depends(api_key_auth),
|
|
session: AsyncSession = Depends(get_session),
|
|
):
|
|
raw = await eml.read()
|
|
# Domain für Job.domain aus To/From ableiten
|
|
try:
|
|
msg = BytesParser(policy=policy.default).parsebytes(raw)
|
|
domain = _guess_domain_from_addresses(msg.get("To")) or _guess_domain_from_addresses(msg.get("From"))
|
|
except Exception:
|
|
domain = "unknown.local"
|
|
|
|
payload = {
|
|
"mailbox_id": str(mailbox_id),
|
|
"raw_eml_b64": base64.b64encode(raw).decode("ascii"),
|
|
}
|
|
job_id, task_id = await enqueue_job_with_single_task(
|
|
session,
|
|
job_type="mail.store",
|
|
domain=domain,
|
|
payload=payload,
|
|
task_name="mail.store",
|
|
routing_key="mail.store",
|
|
)
|
|
return UploadMailResponse(id=UUID(task_id), message_id=None)
|
|
|
|
|