React Native (@frontmail/react-native)
@frontmail/react-native umožní aplikaci pro iOS nebo Android odesílat e-maily přes vaše šablony
s public key – bez vlastního backendu. Funguje s Expem i s čistým React Native.
Instalace
Sekce “Instalace”Expo:
npx expo install @frontmail/react-native @react-native-async-storage/async-storage react-native-webviewČisté React Native:
npm install @frontmail/react-native @react-native-async-storage/async-storage react-native-webviewnpx pod-installOba další balíčky jsou volitelné peer závislosti:
| Balíček | K čemu je potřeba |
|---|---|
@react-native-async-storage/async-storage |
limitRate, který přežije restart aplikace |
react-native-webview |
<TurnstileWebView> |
Povolte mobilní aplikace
Sekce “Povolte mobilní aplikace”Nativní aplikace neposílají hlavičku Origin ani Referer, takže požadavky z aplikace (bez ohledu
na to, jestli máte nastavené povolené weby) skončí chybou
403 origin_not_allowed, dokud v dashboardu nezapnete
Zabezpečení → Mobilní aplikace → Povolit mobilní aplikace a nekliknete na Uložit. Viz
Nastavení zabezpečení.
Požadavky z webů se dál kontrolují podle seznamu, takže přepínač ochranu vašich webových formulářů neoslabí. Přepínač je potřeba i s prázdným seznamem.
Provider a useSendEmail
Sekce “Provider a useSendEmail”Obalte aplikaci do FrontmailProvider a odesílejte pomocí useSendEmail. Objekt s volbami
udržujte stabilní – definujte ho na úrovni modulu nebo pomocí useMemo:
import { useState } from 'react';import { Button, Text, TextInput, View } from 'react-native';import { FrontmailProvider, useSendEmail } from '@frontmail/react-native';
const frontmailOptions = { publicKey: 'pk_4f2a…', limitRate: { id: 'contact', throttle: 30_000 } };
export default function App() { return ( <FrontmailProvider options={frontmailOptions}> <ContactScreen /> </FrontmailProvider> );}
function ContactScreen() { const { send, status, error } = useSendEmail('svc_01J9…', 'tpl_contact'); const [email, setEmail] = useState(''); const [message, setMessage] = useState('');
return ( <View> <TextInput value={email} onChangeText={setEmail} keyboardType="email-address" autoCapitalize="none" /> <TextInput value={message} onChangeText={setMessage} multiline /> <Button title="Odeslat" disabled={status === 'sending'} onPress={() => send({ email, message })} /> {status === 'sent' && <Text>Děkujeme!</Text>} {status === 'held' && <Text>Přijato – brzy ji doručíme.</Text>} {error && <Text>{error.message}</Text>} </View> );}options přijímá publicKey, apiUrl, retry, limitRate, storageProvider a blockList.
privateKey nepřijímá. Případně můžete předat existujícího klienta:
<FrontmailProvider client={client}>.
useSendEmail(serviceId, templateId) vrací { send, getStatus, status, error, result, reset }.
status přechází idle → sending → sent | held | error. send(params, options?) se
resolvne s výsledkem, nebo při chybě s undefined (chyba je v error) – nikdy nevyhodí výjimku,
takže try/catch nepotřebujete. reset() vrátí hook do stavu idle.
Každý požadavek nese hlavičku X-Frontmail-Client: @frontmail/react-native/<verze>.
Turnstile
Sekce “Turnstile”Pokud šablona vyžaduje Turnstile, vykreslete <TurnstileWebView>
a token předejte do send. Site key nepotřebujete: komponenta ve výchozím stavu používá sdílený
mobilní klíč Frontmailu. Načte ho z GET /v1/public-config
API nastaveného v provideru (s cache, takže jen jednou) a widget Cloudflare zobrazí
v react-native-webview jako vloženou HTML stránku s adresou https://mobile.frontmail.dev – z té
adresy se nic nestahuje.
import { useRef, useState } from 'react';import { Button } from 'react-native';import { TurnstileWebView, useSendEmail } from '@frontmail/react-native';import type { TurnstileWebViewHandle } from '@frontmail/react-native';
function ContactScreen() { const { send, status } = useSendEmail('svc_01J9…', 'tpl_contact'); const turnstile = useRef<TurnstileWebViewHandle>(null); const [token, setToken] = useState<string>();
const onSubmit = async () => { await send({ email, message }, { turnstileToken: token }); // Token jde použít jen jednou – pro další pokus si vyžádejte nový. setToken(undefined); turnstile.current?.reset(); };
return ( <> {/* …pole formuláře… */} <TurnstileWebView ref={turnstile} onToken={setToken} onExpire={() => setToken(undefined)} onError={(e) => console.warn(e.message)} /> <Button title="Odeslat" disabled={!token || status === 'sending'} onPress={onSubmit} /> </> );}Props: onToken a volitelně siteKey, baseUrl, onError, onExpire, theme
(auto | light | dark), size (normal | compact | flexible), action, language,
style a webViewProps (předají se WebView).
WebView je uzamčené na widget: načte jen vloženou stránku (baseUrl) a výzvu Cloudflaru, odkazy ve
widgetu se otevřou v systémovém prohlížeči a do vašich callbacků se dostanou jen zprávy ze stránky
widgetu. webViewProps nemohou přepsat source, originWhitelist, hlídání navigace, onMessage
ani nastavení JavaScriptu a přístupu k souborům.
Požadavky z aplikace nemají hlavičku Origin, takže jejich tokeny Frontmail ověří svým sdíleným
mobilním tajným klíčem. Vlastní klíče Turnstile k tomu nepotřebujete – se zapnutým Povolit
mobilní aplikace můžete CAPTCHA u šablon aplikace zapnout, i když organizace klíče zatím nemá.
Vlastní site key
Sekce “Vlastní site key”Pokud chcete místo toho použít vlastní widget Turnstile, předejte siteKey i baseUrl:
<TurnstileWebView ref={turnstile} siteKey="YOUR_TURNSTILE_SITE_KEY" baseUrl="https://example.com" onToken={setToken}/>SDK pak tokeny z tohoto widgetu automaticky posílá s turnstile_key: "org" a Frontmail je ověří
secret key ze Zabezpečení → Ochrana proti botům (Turnstile).
Token platí asi 5 minut a jde použít jen jednou: po každém odeslání, úspěšném i neúspěšném,
zavolejte ref.current.reset().
limitRate a úložiště
Sekce “limitRate a úložiště”limitRate omezuje odesílání přímo v zařízení, třeba na nejvýš jednu zprávu za 30 sekund.
V React Native neexistuje location.pathname, takže vždy nastavte limitRate.id:
import AsyncStorage from '@react-native-async-storage/async-storage';import { asyncStorageProvider } from '@frontmail/react-native';
const frontmailOptions = { publicKey: 'pk_4f2a…', limitRate: { id: 'contact', throttle: 30_000 }, storageProvider: asyncStorageProvider(AsyncStorage),};Bez storageProvider použije SDK AsyncStorage, pokud je nainstalovaný; jinak si limit drží jen
v paměti (po restartu aplikace se vynuluje) a při vývoji vypíše varování. Paměťové úložiště
zvolíte výslovně pomocí memoryStorageProvider().
limitRate chrání jen před nechtěným opakovaným ťuknutím – skutečná ochrana je na serveru (viz
Zabezpečení).
getStatus
Sekce “getStatus”getStatus() z hooku zjistí stav doručení poslední přijaté zprávy. Pro všechno ostatní vrací
useFrontmail() klienta z provideru (send, getStatus):
import { useFrontmail } from '@frontmail/react-native';
const client = useFrontmail();const status = await client.getStatus(messageId, { token });Opakování a idempotence
Sekce “Opakování a idempotence”Chyby sítě, 5xx a 429 se automaticky opakují a všechny pokusy jednoho odeslání sdílejí stejný
idempotency key, takže opakování e-mail nikdy nepošle dvakrát. Klíče jsou UUID v4 – SDK používá
crypto.randomUUID a na Hermesu, který ho nemá, přejde na vlastní generátor. Viz
Retry a idempotence.
Typované parametry
Sekce “Typované parametry”S vygenerovanými typy (npx frontmail types rozšíří
@frontmail/react-native) typově kontroluje useSendEmail('svc_…', 'tpl_contact').send({...})
parametry dané šablony.
Chyby
Sekce “Chyby”error je FrontmailError s vlastnostmi code, status a message. Jak reagovat na jednotlivé
kódy, popisuje Zpracování chyb.
Zabezpečení
Sekce “Zabezpečení”- Do aplikace patří jen public key (
pk_…). Cokoli v balíčku aplikace se dá vytáhnout, takže private key v ní je jako zveřejněný. Viz Public key a private key. - Se zapnutým Povolit mobilní aplikace přijmeme požadavky bez hlavičky
Originodkudkoli – poslat je může jakýkoli skript, který zná váš public key. Spolehněte se na limit na IP adresu, Turnstile u všech šablon, které aplikace používá, a na seznam blokovaných hodnot.
Ukázkový projekt: examples/react-native.