Resend
Scan inbound emails for phishing with brin before your application processes them
Resend is an email API for developers that supports both sending and receiving emails. By wiring brin into Resend's inbound webhook pipeline, you can scan every incoming message for phishing, credential harvesting, and social engineering before your application processes it.
##Prerequisites
- A Resend account and API key
- A receiving domain configured in Resend
- A publicly reachable HTTPS endpoint to receive webhooks
##How it works
Resend fires an email.received webhook when a message arrives at your receiving domain. The webhook payload contains metadata only (from, to, subject, email_id) — not the email body. Your handler fetches the raw email via Resend's Receiving API and POSTs it to brin's /email endpoint. Sending the raw RFC 822 content preserves all headers, MIME structure, and authentication signals (SPF, DKIM) for more accurate phishing detection. If the verdict is suspicious or dangerous, the handler discards the email or triggers an alert.
##Setup
1. Configure an email.received webhook
In the Resend dashboard, add a webhook subscribed to the email.received event pointing at your handler URL. You can also create it via the SDK:
import resend
resend.api_key = "re_..."
resend.Webhooks.create({
"url": "https://your-server.com/webhooks/resend",
"events": ["email.received"],
})import { Resend } from "resend";
const resend = new Resend("re_...");
await resend.webhooks.create({
url: "https://your-server.com/webhooks/resend",
events: ["email.received"],
});2. Build a webhook handler that scans with brin
When an email.received event arrives, fetch the raw email from the Receiving API and POST it to brin for analysis.
import httpx
import resend
from fastapi import FastAPI, Request
app = FastAPI()
resend.api_key = "re_..."
@app.post("/webhooks/resend")
async def handle_email_received(request: Request):
event = await request.json()
if event.get("type") != "email.received":
return {"status": "ignored"}
email = resend.Emails.Receiving.get(email_id=event["data"]["email_id"])
async with httpx.AsyncClient() as http:
eml = await http.get(email["raw"]["download_url"])
brin_resp = await http.post(
"https://api.brin.sh/email",
content=eml.content,
headers={"Content-Type": "text/plain"},
)
result = brin_resp.json()
verdict = result.get("verdict", "safe")
if verdict in ("suspicious", "dangerous"):
print(f"Blocked email from {email.get('from')} — verdict: {verdict}, score: {result.get('score')}")
return {"status": "blocked", "verdict": verdict}
process_email(email)
return {"status": "processed"}import { Resend } from "resend";
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
const resend = new Resend("re_...");
export const POST = async (request: NextRequest) => {
const event = await request.json();
if (event.type !== "email.received") {
return NextResponse.json({ status: "ignored" });
}
const { data: email } = await resend.emails.receiving.get(
event.data.email_id,
);
const eml = await fetch(email.raw.downloadUrl);
const emlBody = await eml.text();
const brinResp = await fetch("https://api.brin.sh/email", {
method: "POST",
headers: { "Content-Type": "text/plain" },
body: emlBody,
});
const result = await brinResp.json();
const verdict = result.verdict ?? "safe";
if (verdict === "suspicious" || verdict === "dangerous") {
console.log(`Blocked email from ${email.from} — verdict: ${verdict}, score: ${result.score}`);
return NextResponse.json({ status: "blocked", verdict });
}
processEmail(email);
return NextResponse.json({ status: "processed" });
};3. Deploy and test
Deploy your webhook handler and send a test email to your Resend receiving address. Check the logs to confirm brin is scanning each message and returning a verdict.
##What gets detected
brin checks every email for the threat types listed under Web threats:
| Threat | Description |
|---|---|
| Phishing | Credential harvesting forms or deceptive login pages |
| Social engineering | Deceptive content designed to manipulate agent decisions |
| Cloaking | Content that shows different material to agents vs. humans |
| Exfiltration sinks | Hidden redirects or JS designed to exfiltrate agent session data |
Each threat is assigned a severity (critical, high, medium, low). See Threat Detection for the full taxonomy.
##Using the response
The brin response follows the standard API format:
{
"score": 15,
"verdict": "dangerous",
"confidence": "high",
"threats": [
{
"type": "phishing",
"severity": "critical",
"detail": "Credential harvesting form targeting Google login"
}
]
}You can also read verdicts from response headers (x-brin-verdict, x-brin-score) for lightweight checks without parsing JSON.
On this page