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

Mailbeam
Vue 3 + Composition APIIntermedio20 minutiAggiornato a gennaio 2025

Verifica delle email in Vue 3

Questo tutorial costruisce un composable riutilizzabile useEmailVerification per la Composition API di Vue 3. Dà un riscontro immediato mentre la persona scrive — valido, non valido oppure «intendevi gmail.com?» — tenendo la tua chiave segreta al sicuro sul server.

Che cosa costruirai

  • Un piccolo endpoint sul server che fa da proxy alla verifica (così la chiave non arriva mai al browser)
  • Un composable useEmailVerification con debounce che restituisce stato reattivo
  • Un modulo di registrazione con stato in linea, suggerimenti sui refusi e una riverifica all'invio

Prerequisiti

  • Vue 3 (Vite o Nuxt) con TypeScript
  • Una rotta di backend sotto il tuo controllo (Node, Python, eccetera) per il proxy
  • Una chiave API di Mailbeam (iscriviti gratis)

Passo 1 — Aggiungi un endpoint di verifica sul server

Non chiamare mai Mailbeam direttamente dal browser: esporresti la tua chiave. Aggiungi un proxy sottile nel tuo backend. Eccolo in Node/Express:

// server/routes/verify-email.js
// Non ci sono ancora SDK: questo è il wrapper di 12 righe di /docs/quickstart.
import { verifyEmail } from "./lib/mailbeam";

export async function verifyEmail(req, res) {
  const { email } = req.body;
  if (!email) return res.status(400).json({ error: "email mancante" });

  try {
    const { valid, score, reason, didYouMean } = await verifyEmail(email);
    res.json({ acceptable: valid && score >= 60, reason, didYouMean });
  } catch (err) {
    // Lascia passare: non bloccare l'interfaccia per un errore dell'API
    res.json({ acceptable: true, reason: null, didYouMean: null });
  }
}

Passo 2 — Crea il composable

// src/composables/useEmailVerification.ts
import { ref, watch } from "vue";

type Status = "idle" | "checking" | "valid" | "invalid" | "error";

export function useEmailVerification(emailRef: import("vue").Ref<string>) {
  const status = ref<Status>("idle");
  const reason = ref<string | null>(null);
  const suggestion = ref<string | null>(null);

  let controller: AbortController | null = null;
  let timer: ReturnType<typeof setTimeout> | null = null;

  async function check(email: string) {
    controller?.abort();
    controller = new AbortController();
    status.value = "checking";

    try {
      const res = await fetch("/api/verify-email", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email }),
        signal: controller.signal,
      });
      const data = await res.json();
      suggestion.value = data.didYouMean ?? null;
      if (data.acceptable) {
        status.value = "valid";
        reason.value = null;
      } else {
        status.value = "invalid";
        reason.value = data.reason ?? "invalid_email";
      }
    } catch (err) {
      if ((err as Error).name === "AbortError") return;
      status.value = "error"; // nell'interfaccia lascia passare
      reason.value = null;
    }
  }

  // Debounce: aspetta 500 ms dopo che si è smesso di scrivere
  watch(emailRef, (email) => {
    if (timer) clearTimeout(timer);
    suggestion.value = null;

    if (!email || !email.includes("@")) {
      status.value = "idle";
      return;
    }
    timer = setTimeout(() => check(email), 500);
  });

  return { status, reason, suggestion };
}

Passo 3 — Collegalo a un modulo

<!-- src/components/SignupForm.vue -->
<script setup lang="ts">
import { ref, computed } from "vue";
import { useEmailVerification } from "@/composables/useEmailVerification";

const email = ref("");
const password = ref("");
const { status, reason, suggestion } = useEmailVerification(email);

const canSubmit = computed(
  () => status.value === "valid" && password.value.length >= 8
);

async function onSubmit() {
  // Riverifica sul server all'invio: non fidarti mai del solo stato del client
  const res = await fetch("/api/signup", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ email: email.value, password: password.value }),
  });
  if (!res.ok) {
    // mostra l'errore di validazione del server
  }
}

function applySuggestion() {
  if (suggestion.value) email.value = suggestion.value;
}
</script>

<template>
  <form @submit.prevent="onSubmit">
    <label for="email">Email</label>
    <input id="email" v-model="email" type="email" autocomplete="email" />

    <p v-if="status === 'checking'" class="hint">Controllo in corso…</p>
    <p v-else-if="status === 'valid'" class="hint ok">✓ Sembra a posto</p>
    <p v-else-if="status === 'invalid'" class="hint err">
      Questa email sembra non recapitabile ({{ reason }}).
    </p>

    <p v-if="suggestion" class="hint">
      Intendevi
      <button type="button" @click="applySuggestion">{{ suggestion }}</button>?
    </p>

    <input v-model="password" type="password" autocomplete="new-password" />

    <button type="submit" :disabled="!canSubmit">Crea account</button>
  </form>
</template>

Passo 4 — Verifica sempre anche sul server

Il composable migliora l'esperienza, ma lo stato del client si può falsificare o saltare. Il tuo gestore di /api/signup deve eseguire la stessa verifica prima di creare l'utente: riusa la logica del proxy del passo 1.

Buone pratiche

PraticaPerché
Debounce di ~500 msUna chiamata per pausa, non per tasto premuto
Interrompere le richieste in voloEvita risultati fuori ordine mentre si scrive
Passare dal proxy sul tuo serverTiene la chiave API fuori dal client
Riverificare all'invioLo stato del client è indicativo, non autorevole
Mostrare didYouMeanSalva chi scrive gmial.com

Lista di controllo per la produzione

  • Endpoint di verifica con limite di ritmo per IP
  • MAILBEAM_KEY solo sul server
  • Il gestore dell'invio riverifica sul server
  • L'interfaccia lascia passare se il controllo va in errore
  • Gli stati di caricamento e di errore sono accessibili (aria-live)

Prossimi passi