Beta privataMailbeam è in beta privata: l'API pubblica non è ancora aperta.Iscriviti alla lista d'attesa

Mailbeam
Clerk + Next.jsIntermedio20 minutiAggiornato a gennaio 2025

Verifica delle email con Clerk

Clerk supporta i webhook per gli eventi del ciclo di vita dell'utente, compreso user.created. Clerk non ha un blocco nativo precedente alla creazione, ma puoi combinare un webhook con i metadati utente di Clerk per marcare le registrazioni non valide e cancellarle subito, oppure usare il modello della redirezione precedente alla registrazione.

Questo tutorial usa il modello consigliato: verificare l'email in un endpoint sul server prima di chiamare signUp.create di Clerk.

Prerequisiti

  • Un account Clerk e un progetto Next.js con @clerk/nextjs
  • Una chiave API di Mailbeam (iscriviti gratis)

Preparazione

npm install svix  # svix è la libreria dei webhook di Clerk

Endpoint di verifica sul server

// app/api/verify-email/route.ts
import { NextResponse } from "next/server";
// Non ci sono ancora SDK: questo è il wrapper di 12 righe di /docs/quickstart.
import { verifyEmail } from "./lib/mailbeam";

export async function POST(req: Request) {
  const { email } = await req.json();

  if (!email) {
    return NextResponse.json({ error: "email mancante" }, { status: 400 });
  }

  try {
    const { valid, score, reason } = await verifyEmail(email);

    return NextResponse.json({ valid, score, reason });
  } catch {
    // Lascia passare
    return NextResponse.json({ valid: true, score: 50, reason: null });
  }
}

Modulo di registrazione tuo

// app/signup/CustomSignupForm.tsx
"use client";

import { useSignUp } from "@clerk/nextjs";
import { useState } from "react";

export function CustomSignupForm() {
  const { signUp, setActive } = useSignUp();
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState<string | null>(null);
  const [loading, setLoading] = useState(false);

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    setLoading(true);
    setError(null);

    // Passo 1: verifica l'email sul server prima di chiamare Clerk
    const verifyRes = await fetch("/api/verify-email", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ email }),
    });

    const { valid, score, reason } = await verifyRes.json();

    if (!valid || score < 60) {
      setError(
        reason === "disposable_domain"
          ? "Usa un indirizzo email permanente."
          : "Inserisci un indirizzo email valido."
      );
      setLoading(false);
      return;
    }

    // Passo 2: prosegui con la registrazione in Clerk
    try {
      const result = await signUp!.create({ emailAddress: email, password });

      if (result.status === "complete") {
        await setActive!({ session: result.createdSessionId });
        window.location.href = "/dashboard";
      }
    } catch (err: unknown) {
      setError((err as { errors?: { message: string }[] })?.errors?.[0]?.message ?? "La registrazione non è riuscita.");
    } finally {
      setLoading(false);
    }
  }

  return (
    <form onSubmit={handleSubmit} className="space-y-4 max-w-sm">
      {error && (
        <p role="alert" className="rounded-lg bg-destructive/10 p-3 text-sm text-destructive">
          {error}
        </p>
      )}
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Indirizzo email"
        className="w-full rounded-lg border border-border px-3 py-2 text-sm bg-background"
        required
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="Password"
        className="w-full rounded-lg border border-border px-3 py-2 text-sm bg-background"
        required
      />
      <button
        type="submit"
        disabled={loading}
        className="w-full rounded-lg bg-primary px-4 py-2 text-sm font-medium text-primary-foreground disabled:opacity-60"
      >
        {loading ? "Creazione dell'account…" : "Crea account"}
      </button>
    </form>
  );
}

Buone pratiche

  • Verifica prima di chiamare Clerk, non dopo: eviti utenti orfani non verificati
  • Tieni leggero l'endpoint di verifica: deve solo chiamare Mailbeam e restituire
  • Usa reason per dare messaggi di errore concreti

Prossimi passi