Ako vytvoriť kontaktný formulár pre iOS v Swifte a SwiftUI
Kontaktný formulár v SwiftUI, ktorý vám každú správu pošle e-mailom cez vašu vlastnú schránku – bez backendu a bez SMTP hesla v aplikácii. So Swift balíčkom od Frontmailu.
Aktualizované:
Do aplikácie pre iOS pridáte kontaktný formulár v SwiftUI so Swift balíčkom Frontmail. Aplikácia obsahuje iba verejný kľúč; Frontmail odošle e-mail cez vašu schránku, takže v aplikácii nie je žiadne SMTP heslo a nemusíte udržiavať žiadny server.
Potrebujete: bezplatný účet Frontmail, projekt v Xcode so SwiftUI a zhruba pätnásť minút.
1. Pripojte schránku a vytvorte šablónu
- E-mailové služby → Pridať službu: pripojte Gmail, Outlook, SMTP alebo transakčného poskytovateľa, zaškrtnite Nastaviť ako predvolenú, Overiť a uložiť.
- Šablóny → Z galérie → Kontaktný formulár → Použiť šablónu. Povinné parametre:
name,email,message; nepovinné:phone,topic. - Z karty Kód skopírujte ID šablóny (
tpl_…).
2. Povoľte mobilné aplikácie
- Zabezpečenie → Mobilné aplikácie → Povoliť mobilné aplikácie → Uložiť. Aplikácie
neposielajú hlavičku
Origin, takže dovtedy API odpovedáorigin_not_allowed. - Šablóna → Nastavenia → Ochrana → Vyžadovať CAPTCHA (Turnstile). Aplikácie používajú zdieľaný widget Turnstile od Frontmailu; kľúče od Cloudflare nepotrebujete.
3. Pridajte balíček
V Xcode zvoľte File → Add Package Dependencies…, zadajte
https://github.com/frontmail-dev/frontmail-swift a knižnicu Frontmail pridajte do targetu
aplikácie. Potom si z časti o Turnstile v dokumentácii iOS SDK skopírujte do projektu
TurnstileView – malý UIViewRepresentable okolo WKWebView, ktorý patrí vám.
4. Vytvorte formulár
import SwiftUI
import Frontmail
let frontmail = try! Frontmail(publicKey: "pk_…") // create once, share
struct ContactMessage: Encodable {
let name: String
let email: String
let message: String
}
struct ContactView: View {
@State private var name = ""
@State private var email = ""
@State private var message = ""
@State private var widget: Turnstile.Widget?
@State private var token: String?
@State private var resetID = 0
@State private var info = ""
var body: some View {
Form {
TextField("Name", text: $name)
TextField("Email", text: $email)
.keyboardType(.emailAddress)
.textInputAutocapitalization(.never)
TextField("Message", text: $message, axis: .vertical)
.lineLimit(4...8)
if let widget {
TurnstileView(widget: widget, size: .flexible, resetID: resetID) { event in
if case let .token(t) = event { token = t } else { token = nil }
}
.frame(height: Turnstile.Size.flexible.recommendedHeight)
}
Button("Send") { Task { await send() } }
.disabled(token == nil)
Text(info)
}
.task { widget = try? await Turnstile.widget(client: frontmail) }
}
private func send() async {
guard let widget, let token else { return }
defer { self.token = nil; resetID += 1 } // a token works only once
do {
_ = try await frontmail.send(
templateID: "tpl_…",
params: ContactMessage(name: name, email: email, message: message),
options: SendOptions(turnstileToken: token, turnstileKey: widget.turnstileKey)
)
info = "Thank you! We’ll get back to you soon."
} catch let error as FrontmailError {
info = error.message
} catch {
info = error.localizedDescription
}
}
}
Ako parametre poslúži ľubovoľná štruktúra Encodable, takže názvy polí vám skontroluje kompilátor.
Sieťové chyby a odpovede 5xx sa opakujú s jedným idempotency kľúčom – ani pri nestabilnom
pripojení nevzniknú duplicitné e-maily.
5. Vyskúšajte to
Spustite aplikáciu v simulátore alebo na zariadení, vyplňte formulár a ťuknite na Send. E-mail vám príde do schránky a zobrazí sa v dashboarde v časti História.
origin_not_allowed– Povoliť mobilné aplikácie je vypnuté alebo neuložené.captcha_required– zatiaľ chýba token Turnstile; Send zostane neaktívne, kým sa overenie nedokončí.invalid_template_params– povinné pole je prázdne alebo e-mail nie je platný.
Keď vám dôjdu kredity, správa sa prijme so stavom
.helda po dobití sa automaticky odošle – nič sa nestratí.
Ďalšie kroky
- Potvrďte používateľovi prijatie správy šablónou Automatická odpoveď: ďakujeme za správu z galérie.
- Pošlite
SendOptions(locale: Locale.preferredLanguages.first)a použije sa jazyková verzia šablóny v jazyku používateľa.


