Guides/ Python
Guides

Python

A shared client with httpx, then FastAPI, Django and Flask handlers.

The client

import os
import time
import httpx

SPAMEX = httpx.Client(
    base_url="https://api.spamex.dev",
    headers={"Authorization": f"Bearer {os.environ['SPAMEX_KEY']}"},
    timeout=5.0,
)

BOT = {"HONEYPOT_FILLED", "FAST_SUBMIT", "URL_IN_NAME", "DUP_KNOWN_SPAM",
       "IP_REPUTATION_BAD", "EMAIL_REPUTATION_BAD", "EMAIL_DOMAIN_REPUTATION_BAD"}


def classify(fields: dict, ip: str | None, user_agent: str | None) -> dict | None:
    try:
        r = SPAMEX.post("/v1/classify", json={
            "name": fields.get("name", ""),
            "email": fields.get("email", ""),
            "subject": fields.get("subject", ""),
            "message": fields.get("message", ""),
            "honeypot": fields.get("website", ""),          # your hidden trap field
            "form_load_ts": _num(fields.get("form_load_ts")),
            "submit_ts": time.time(),
            "ip": ip,
            "user_agent": user_agent,
        })
        return r.json() if r.status_code == 200 else None   # None = fail open
    except httpx.HTTPError:
        return None


def bucket(v: dict | None) -> str:
    if not v or v["label"] == "ham":
        return "deliver"
    return "bot" if BOT & set(v["reasons"]) else "review"


def _num(v):
    try:
        return float(v) if v not in (None, "") else None
    except ValueError:
        return None

FastAPI

from fastapi import FastAPI, Form, Request

app = FastAPI()


@app.post("/contact")
async def contact(request: Request, name: str = Form(""), email: str = Form(""), subject: str = Form(""),
                  message: str = Form(...), website: str = Form(""), form_load_ts: str = Form("")):
    fields = dict(name=name, email=email, subject=subject, message=message, website=website, form_load_ts=form_load_ts)
    v = classify(fields, request.client.host, request.headers.get("user-agent"))
    match bucket(v):
        case "bot":
            pass                                  # drop silently
        case "review":
            quarantine(fields, v)                 # keep v["id"] for feedback
        case _:
            deliver(fields, v)
    return {"ok": True}

Django

def contact(request):
    if request.method == "POST":
        ip = request.META.get("HTTP_X_FORWARDED_FOR", request.META.get("REMOTE_ADDR", "")).split(",")[0].strip()
        v = classify(request.POST.dict(), ip, request.META.get("HTTP_USER_AGENT"))
        match bucket(v):
            case "bot":
                pass
            case "review":
                quarantine(request.POST, v)
            case _:
                deliver(request.POST, v)
    return render(request, "thanks.html")

Flask

@app.post("/contact")
def contact():
    v = classify(request.form.to_dict(), request.remote_addr, request.user_agent.string)
    ...

Feedback

SPAMEX.post("/v1/feedback", json={"id": verdict_id, "label": "ham"})
↑↓ navigate↵ openDocs and blog