integrations

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

##How it works

100%

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:

Python
import resend
 
resend.api_key = "re_..."
 
resend.Webhooks.create({
    "url": "https://your-server.com/webhooks/resend",
    "events": ["email.received"],
})
TypeScript
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.

Python
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"}
TypeScript
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:

ThreatDescription
PhishingCredential harvesting forms or deceptive login pages
Social engineeringDeceptive content designed to manipulate agent decisions
CloakingContent that shows different material to agents vs. humans
Exfiltration sinksHidden 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:

JSON
{
  "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.