Vai al contenuto

Come creare un modulo di contatto in React Native (ed Expo) che invia email

Un modulo di contatto in React Native che ti invia ogni messaggio via email, con stato di invio, protezione dai bot e senza backend. Funziona con Expo e con React Native puro.

Aggiornato:

Il video è in inglese; i passaggi qui sotto sono il tutorial completo.

Aggiungerai un modulo di contatto a un’app React Native o Expo con il pacchetto @frontmail/react-native: un provider, un hook useSendEmail che tiene traccia dello stato di invio e un componente Turnstile già pronto contro i bot. L’email parte dalla tua casella di posta.

Ti serve: un account Frontmail gratuito, un progetto Expo o React Native e una decina di minuti.

1. Collega la tua casella e crea il modello

  1. Servizi email → Aggiungi servizio: collega Gmail, Outlook, SMTP o un provider transazionale, seleziona Imposta come predefinito, poi Verifica e salva.
  2. Modelli → Dalla galleria → Modulo di contatto → Usa modello. Parametri obbligatori: name, email, message; facoltativi: phone, topic.
  3. Copia l’ID del modello (tpl_…) dalla scheda Snippet.

2. Consenti le app mobile

  • Sicurezza → App mobile → Consenti app mobile → Salva. Le app non inviano l’header Origin, quindi senza questo interruttore l’API risponde origin_not_allowed.
  • Modello → Impostazioni → Protezione → Richiedi CAPTCHA (Turnstile). L’app usa il widget Turnstile condiviso di Frontmail; non ti servono chiavi Cloudflare.

3. Installa

npx expo install @frontmail/react-native @react-native-async-storage/async-storage react-native-webview

In un progetto React Native puro usa npm i con gli stessi pacchetti ed esegui npx pod-install.

4. Crea il modulo

import { useRef, useState } from 'react';
import { Button, Text, TextInput, View } from 'react-native';
import { FrontmailProvider, TurnstileWebView, useSendEmail, type TurnstileWebViewHandle } from '@frontmail/react-native';

const options = { publicKey: 'pk_…' }; // keep the object stable

export default function App() {
  return (
    <FrontmailProvider options={options}>
      <ContactForm />
    </FrontmailProvider>
  );
}

function ContactForm() {
  const { send, status, error } = useSendEmail(null, 'tpl_…'); // null = default service
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [message, setMessage] = useState('');
  const [token, setToken] = useState<string>();
  const turnstile = useRef<TurnstileWebViewHandle>(null);

  const onSend = async () => {
    await send({ name, email, message }, { turnstileToken: token });
    setToken(undefined);
    turnstile.current?.reset(); // a token works only once
  };

  if (status === 'sent' || status === 'held') return <Text>Thank you! We’ll get back to you soon.</Text>;

  return (
    <View style={{ gap: 12, padding: 16 }}>
      <TextInput placeholder="Name" value={name} onChangeText={setName} />
      <TextInput placeholder="Email" value={email} onChangeText={setEmail} keyboardType="email-address" autoCapitalize="none" />
      <TextInput placeholder="Message" value={message} onChangeText={setMessage} multiline />
      <TurnstileWebView ref={turnstile} onToken={setToken} />
      <Button title="Send" disabled={!token || status === 'sending'} onPress={onSend} />
      {error && <Text>{error.message}</Text>}
    </View>
  );
}

send non genera mai eccezioni: restituisce il risultato oppure undefined, e status passa da idle a sending e poi a sent, held o error. I nuovi tentativi dopo un errore di rete riusano un’unica chiave di idempotenza, così chi scrive dal treno non ti manda mai due volte lo stesso messaggio.

5. Provalo

Avvia l’app (npx expo start), compila il modulo e tocca Send. L’email arriva nella tua casella e in Cronologia nella dashboard.

  • origin_not_allowed – Consenti app mobile è disattivato o non è stato salvato.
  • captcha_required – la verifica Turnstile non è ancora finita; il pulsante resta disattivato finché non c’è un token.
  • invalid_template_params – un campo obbligatorio è vuoto oppure l’email non è valida.

held significa che il messaggio è stato accettato mentre i tuoi crediti erano esauriti. Parte automaticamente appena ricarichi: non va perso nulla.

Prossimi passi

  • Aggiungi limitRate: { id: 'contact', throttle: 30_000 } alle opzioni del provider per consentire un messaggio ogni 30 secondi per dispositivo.
  • Invia una conferma all’utente con il modello Risposta automatica: grazie per il messaggio della galleria.
Tutti i tutorial