Przejdź do treści

Jak zrobić formularz kontaktowy na iOS w Swifcie i SwiftUI

Formularz kontaktowy w SwiftUI, który wysyła Ci każdą wiadomość e-mailem przez Twoją własną skrzynkę – bez backendu i bez hasła SMTP w aplikacji. Korzysta z pakietu Frontmail dla Swifta.

Zaktualizowano:

Film jest po angielsku; poniżej znajdziesz pełny samouczek krok po kroku.

Dodasz formularz kontaktowy do aplikacji na iOS w SwiftUI z pakietem Frontmail dla Swifta. Aplikacja zna tylko klucz publiczny; e-mail wysyła Frontmail przez Twoją skrzynkę, więc w aplikacji nie ma hasła SMTP, a Ty nie musisz utrzymywać żadnego serwera.

Potrzebujesz: darmowego konta Frontmail, projektu w Xcode ze SwiftUI i około piętnastu minut.

1. Podłącz skrzynkę i utwórz szablon

  1. Usługi e-mail → Dodaj usługę: podłącz Gmail, Outlook, SMTP albo dostawcę e-maili transakcyjnych, zaznacz Ustaw jako domyślną, Zweryfikuj i zapisz.
  2. Szablony → Z galerii → Formularz kontaktowy → Użyj szablonu. Parametry wymagane: name, email, message; opcjonalne: phone, topic.
  3. Skopiuj ID szablonu (tpl_…) z zakładki Kod.

2. Zezwól na aplikacje mobilne

  • Bezpieczeństwo → Aplikacje mobilne → Zezwól na aplikacje mobilne → Zapisz. Aplikacje nie wysyłają nagłówka Origin, więc do tego czasu API odpowiada origin_not_allowed.
  • Szablon → Ustawienia → Ochrona → Wymagaj CAPTCHA (Turnstile). Aplikacje korzystają ze wspólnego widżetu Turnstile Frontmail; klucze Cloudflare nie są potrzebne.

3. Dodaj pakiet

W Xcode wybierz File → Add Package Dependencies…, wpisz https://github.com/frontmail-dev/frontmail-swift i dodaj bibliotekę Frontmail do targetu aplikacji. Potem skopiuj do projektu TurnstileView z sekcji o Turnstile w dokumentacji iOS SDK – to mały UIViewRepresentable wokół WKWebView, który jest Twój.

4. Zbuduj formularz

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
        }
    }
}

Jako parametrów możesz użyć dowolnej struktury Encodable, więc nazwy pól sprawdza za Ciebie kompilator. Błędy sieci i odpowiedzi 5xx są ponawiane z jednym kluczem idempotencji – żadnych zduplikowanych e-maili przy niestabilnym połączeniu.

5. Przetestuj

Uruchom aplikację w symulatorze lub na urządzeniu, wypełnij formularz i stuknij Send. E-mail trafi do Twojej skrzynki i pojawi się w panelu w sekcji Historia.

  • origin_not_allowed – opcja Zezwól na aplikacje mobilne jest wyłączona albo niezapisana.
  • captcha_required – nie ma jeszcze tokenu Turnstile; Send pozostaje nieaktywny, dopóki weryfikacja się nie zakończy.
  • invalid_template_params – wymagane pole jest puste albo e-mail jest nieprawidłowy.

Gdy skończą Ci się kredyty, wiadomość zostanie przyjęta ze statusem .held i wysłana automatycznie po doładowaniu – nic nie przepada.

Co dalej

  • Potwierdzaj użytkownikowi otrzymanie wiadomości szablonem Automatyczna odpowiedź: dziękujemy za wiadomość z galerii.
  • Wysyłaj SendOptions(locale: Locale.preferredLanguages.first), żeby użyć wersji językowej szablonu w języku użytkownika.
Wszystkie samouczki