React Native (@frontmail/react-native)
@frontmail/react-native pozwala aplikacji na iOS lub Androida wysyłać e-maile przez twoje szablony
z kluczem publicznym – bez własnego backendu. Działa z Expo i z czystym React Native.
Instalacja
Dział zatytułowany „Instalacja”Expo:
npx expo install @frontmail/react-native @react-native-async-storage/async-storage react-native-webviewCzysty React Native:
npm install @frontmail/react-native @react-native-async-storage/async-storage react-native-webviewnpx pod-installDwa dodatkowe pakiety to opcjonalne peer dependencies:
| Pakiet | Potrzebny do |
|---|---|
@react-native-async-storage/async-storage |
limitRate, który przetrwa restart aplikacji |
react-native-webview |
<TurnstileWebView> |
Zezwól na aplikacje mobilne
Dział zatytułowany „Zezwól na aplikacje mobilne”Aplikacje natywne nie wysyłają nagłówka Origin ani Referer, więc żądania z aplikacji są
odrzucane (niezależnie od tego, czy masz ustawione dozwolone domeny)
z błędem 403 origin_not_allowed, dopóki nie włączysz
w panelu Bezpieczeństwo → Aplikacje mobilne → Zezwól na aplikacje mobilne i nie klikniesz
Zapisz. Zobacz Ustawienia bezpieczeństwa.
Żądania ze stron są nadal sprawdzane z listą, więc przełącznik nie osłabia ochrony twoich formularzy na stronach. Przełącznik jest wymagany nawet przy pustej liście.
Provider i useSendEmail
Dział zatytułowany „Provider i useSendEmail”Owiń aplikację w FrontmailProvider i wysyłaj przez useSendEmail. Obiekt z opcjami powinien być
stabilny – zdefiniuj go na poziomie modułu albo przez 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="Wyślij" disabled={status === 'sending'} onPress={() => send({ email, message })} /> {status === 'sent' && <Text>Dziękujemy!</Text>} {status === 'held' && <Text>Otrzymaliśmy – wkrótce ją dostarczymy.</Text>} {error && <Text>{error.message}</Text>} </View> );}options przyjmuje publicKey, apiUrl, retry, limitRate, storageProvider i blockList.
privateKey nie jest akceptowany. Możesz też przekazać istniejącego klienta:
<FrontmailProvider client={client}>.
useSendEmail(serviceId, templateId) zwraca { send, getStatus, status, error, result, reset }.
status przechodzi idle → sending → sent | held | error. send(params, options?) zwraca
wynik albo – przy błędzie – undefined (błąd jest w error); nigdy nie odrzuca promise’a, więc nie
potrzebujesz try/catch. reset() przywraca hook do stanu idle.
Żeby wysłać e-mail w jednym z języków szablonu, przekaż locale
w opcjach: send({ email, message }, { locale: 'de' }) – na przykład język urządzenia
z Intl.DateTimeFormat().resolvedOptions().locale. Nieznane języki przechodzą na ten sam język
bazowy, a potem na język domyślny szablonu; result.locale to użyty język.
Każde żądanie niesie nagłówek X-Frontmail-Client: @frontmail/react-native/<version>.
Turnstile
Dział zatytułowany „Turnstile”Jeśli szablon wymaga Turnstile, wyrenderuj <TurnstileWebView> i przekaż
token do send. Nie potrzebujesz site key: domyślnie komponent używa wspólnego mobilnego klucza
Frontmail. Pobiera go z GET /v1/public-config API
ustawionego w providerze (z cache, więc tylko raz) i pokazuje widget Cloudflare
w react-native-webview jako osadzoną stronę HTML z adresem https://mobile.frontmail.dev – nic
nie jest pobierane z tego adresu.
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 można użyć tylko raz – przy następnej próbie potrzebny jest nowy. setToken(undefined); turnstile.current?.reset(); };
return ( <> {/* …pola… */} <TurnstileWebView ref={turnstile} onToken={setToken} onExpire={() => setToken(undefined)} onError={(e) => console.warn(e.message)} /> <Button title="Wyślij" disabled={!token || status === 'sending'} onPress={onSubmit} /> </> );}Propsy: onToken oraz opcjonalnie siteKey, baseUrl, onError, onExpire, theme
(auto | light | dark), size (normal | compact | flexible), action, language,
style i webViewProps (przekazywane do WebView).
WebView jest ograniczony do widgetu: ładuje tylko osadzoną stronę (baseUrl) i challenge
Cloudflare, linki wewnątrz widgetu otwierają się w przeglądarce systemowej, a do twoich callbacków
docierają tylko wiadomości ze strony widgetu. webViewProps nie może nadpisać source,
originWhitelist, strażnika nawigacji, onMessage ani ustawień JavaScriptu i dostępu do plików.
Żądania z aplikacji nie mają nagłówka Origin, więc Frontmail weryfikuje ich tokeny wspólnym
mobilnym kluczem tajnym. Nie potrzebujesz do tego własnych kluczy Turnstile – przy włączonym
Zezwól na aplikacje mobilne możesz włączyć CAPTCHA w szablonach używanych przez aplikację, nawet
jeśli twoja organizacja nie ma jeszcze kluczy.
Własny site key
Dział zatytułowany „Własny site key”Żeby zamiast tego użyć własnego widgetu Turnstile, przekaż zarówno siteKey, jak i baseUrl:
<TurnstileWebView ref={turnstile} siteKey="YOUR_TURNSTILE_SITE_KEY" baseUrl="https://example.com" onToken={setToken}/>SDK wysyła wtedy tokeny z tego widgetu automatycznie z turnstile_key: "org", a Frontmail weryfikuje
je kluczem tajnym z Bezpieczeństwo → Ochrona przed botami (Turnstile).
Token jest ważny około 5 minut i można go użyć tylko raz: po każdej wysyłce, udanej lub nie,
wywołaj ref.current.reset().
limitRate i pamięć
Dział zatytułowany „limitRate i pamięć”limitRate ogranicza wysyłanie na urządzeniu, np. do najwyżej jednej wiadomości na 30 sekund.
W React Native nie ma location.pathname, więc zawsze ustawiaj 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 SDK używa AsyncStorage, jeśli jest zainstalowany; w przeciwnym razie trzyma
limit tylko w pamięci (resetuje się po restarcie aplikacji) i w trybie deweloperskim wypisuje
ostrzeżenie. Użyj memoryStorageProvider(), żeby jawnie wybrać przechowywanie w pamięci.
limitRate chroni tylko przed przypadkowym wielokrotnym stuknięciem – prawdziwa ochrona jest na
serwerze (zobacz Bezpieczeństwo).
getStatus
Dział zatytułowany „getStatus”getStatus() z hooka odczytuje status doręczenia ostatniej przyjętej wiadomości. Do wszystkiego
innego useFrontmail() zwraca klienta z providera (send, getStatus):
import { useFrontmail } from '@frontmail/react-native';
const client = useFrontmail();const status = await client.getStatus(messageId, { token });Ponawianie i idempotencja
Dział zatytułowany „Ponawianie i idempotencja”Błędy sieci, 5xx i 429 są ponawiane automatycznie, a wszystkie próby jednej wysyłki używają tego
samego klucza idempotencji, więc ponowienie nigdy nie wyśle e-maila dwa razy. Klucze to UUID v4 –
SDK używa crypto.randomUUID, a na Hermesie, który go nie udostępnia, korzysta z własnego
generatora. Zobacz Ponawianie i idempotencja.
Typowane parametry
Dział zatytułowany „Typowane parametry”Z wygenerowanymi typami (npx frontmail types rozszerza
@frontmail/react-native) useSendEmail('svc_…', 'tpl_contact').send({...}) sprawdza typy
parametrów danego szablonu.
error to FrontmailError z code, status i message. Jak obsłużyć poszczególne kody, opisuje
strona Obsługa błędów.
Bezpieczeństwo
Dział zatytułowany „Bezpieczeństwo”- Do aplikacji wkładaj tylko klucz publiczny (
pk_…). Wszystko w paczce aplikacji da się wyciągnąć, więc klucz prywatny w niej jest tak dobry jak opublikowany. Zobacz Klucze publiczne i prywatne. - Przy włączonym Zezwól na aplikacje mobilne żądania bez nagłówka
Originsą przyjmowane skądkolwiek – może je wysłać każdy skrypt, który zna twój klucz publiczny. Polegaj na limicie na IP, Turnstile w każdym szablonie używanym przez aplikację i liście blokad.
Przykładowy projekt: examples/react-native.