Vai al contenuto
GiovanniLiguori
Bergamo · ItaliaPrenota una call
§ 00 / GIOVANNI
Sistemi agentici per processi documentali: fonti, confini, astensione e traccia.
SCOPING APERTO
Risorse / DM / RESEND7 settembre 2026

Resend e Python: risolvere il blocco Cloudflare WAF (error 1010)

Come risolvere il blocco Cloudflare error 1010 quando chiami api.resend.com da Python urllib: causa, fix per urllib e requests, e come testarlo.

Commenta RESEND sotto il reel7 settembre 2026Giovanni Liguori
Contenuto assistito da AI

Il problema

Una chiamata Python a api.resend.com/emails torna con 1010 Access Denied. Cloudflare blocca la richiesta prima che arrivi a Resend. Nessun messaggio utile: solo il codice di errore.

Questo è successo sul mio sistema. Ho un'integrazione Resend in produzione da febbraio 2026, parte delle 35+ automazioni che girano ogni giorno su 5 piattaforme.

La causa

urllib, la libreria HTTP di default in Python, invia questo header:

User-Agent: Python-urllib/3.x

Cloudflare WAF classifica il client come automatico non identificato e blocca con errore 1010 prima che la richiesta raggiunga l'API. Non è un problema di Resend: è la politica del WAF davanti all'endpoint. Si ripete su qualsiasi API protetta da Cloudflare con regole antibot attive.

Come si manifesta

Il sintomo: la chiamata ritorna 1010 dal livello Cloudflare, non dall'API. Questo significa:

  1. Resend non vede la richiesta
  2. I log di Resend sono vuoti per quella chiamata
  3. Il tuo codice riceve un errore HTTP ma nessuna informazione utile sulla causa

Il guasto è silenzioso: urllib non avvisa sul proprio User-Agent, Cloudflare non spiega perché blocca, e l'API non vede nulla.

Il fix per urllib

Aggiungi un header User-Agent esplicito in ogni richiesta:

import urllib.request
import json

payload = json.dumps({"from": "...", "to": "...", "subject": "..."}).encode()

req = urllib.request.Request(
    "https://api.resend.com/emails",
    data=payload,
    headers={
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
        "User-Agent": "resend-python/1.0"
    }
)
response = urllib.request.urlopen(req)

Il valore dello User-Agent non deve essere specifico: Cloudflare cerca un header presente e plausibile, non un formato certificato. L'importante è che non sia il default di urllib.

Il fix per requests

Se usi requests invece di urllib, il problema è meno comune: requests invia python-requests/2.x.x di default, che Cloudflare di norma tollera. Se riscontri comunque il blocco, aggiungi l'header esplicitamente:

import requests

response = requests.post(
    "https://api.resend.com/emails",
    json=payload,
    headers={
        "Authorization": f"Bearer {api_key}",
        "User-Agent": "resend-python/1.0"
    }
)

Come diagnosticare prima di modificare il codice

Prima di toccare il codice, verifica la causa con curl:

curl -A "test-client/1.0" \
  -H "Authorization: Bearer $RESEND_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"from":"...","to":"...","subject":"test"}' \
  https://api.resend.com/emails

Se con curl passa e con Python no, il problema è l'User-Agent. Confermato.

Perché succede in produzione e non nel test

Nel test spesso si usa curl o requests con il suo UA di default tollerato. In produzione si finisce per usare urllib perché è nella libreria standard, non richiede dipendenze extra e funziona in Cloud Run o Lambda senza install aggiuntivi.

La divergenza User-Agent tra ambiente di test e produzione è sufficiente a far passare il test e bloccare la produzione. Basta un header.

La regola generale

Ogni chiamata a un'API con WAF attivo: controlla cosa manda il client, non solo cosa risponde l'API. Il WAF intercetta prima che la logica applicativa veda la richiesta. Gli errori sembrano venire dall'API ma la causa è a monte.

Sul mio sistema ho aggiunto questi controlli alla checklist di ogni nuova integrazione:

  1. User-Agent esplicito su ogni client HTTP che chiama API esterne
  2. test in isolamento prima dell'integrazione nel sistema principale
  3. log del corpo completo della risposta in caso di 4xx, non solo lo status code

Il controllo è costato meno di 5 minuti. L'assenza del controllo mi aveva già bloccato una notifica importante.

Resend e Python: risolvere il blocco Cloudflare WAF (error 1010) | Giovanni Liguori