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"})