Zum Inhalt springen

Kontaktformular in iOS mit Swift und SwiftUI erstellen

Ein SwiftUI-Kontaktformular, das Ihnen jede Nachricht über Ihr eigenes Postfach schickt – ohne Backend und ohne SMTP-Passwort in der App. Mit dem Frontmail-Swift-Paket.

Aktualisiert:

Das Video ist auf Englisch; die Schritte unten sind das vollständige Tutorial.

Sie fügen einer iOS-App mit SwiftUI und dem Frontmail-Swift-Paket ein Kontaktformular hinzu. Die App enthält nur einen öffentlichen Schlüssel; Frontmail versendet die E-Mail über Ihr Postfach – kein SMTP-Passwort in der App und kein Server, den Sie warten müssen.

Sie brauchen: ein kostenloses Frontmail-Konto, ein Xcode-Projekt mit SwiftUI und etwa fünfzehn Minuten.

1. Postfach verbinden und Vorlage anlegen

  1. E-Mail-Dienste → Dienst hinzufügen: Verbinden Sie Gmail, Outlook, SMTP oder einen Transaktions-Anbieter, aktivieren Sie Als Standard festlegen, dann Prüfen & speichern.
  2. Vorlagen → Aus der Galerie → Kontaktformular → Vorlage verwenden. Pflichtparameter: name, email, message; optional: phone, topic.
  3. Kopieren Sie die Vorlagen-ID (tpl_…) aus dem Tab Snippets.

2. Mobile Apps erlauben

  • Sicherheit → Mobile Apps → Mobile Apps erlauben → Speichern. Apps senden keinen Origin-Header, bis dahin antwortet die API daher mit origin_not_allowed.
  • Vorlage → Einstellungen → Schutz → CAPTCHA verlangen (Turnstile). Apps nutzen das gemeinsame Turnstile-Widget von Frontmail; Cloudflare-Schlüssel brauchen Sie nicht.

3. Paket hinzufügen

Wählen Sie in Xcode File → Add Package Dependencies…, geben Sie https://github.com/frontmail-dev/frontmail-swift ein und fügen Sie die Bibliothek Frontmail Ihrem App-Target hinzu. Kopieren Sie dann TurnstileView aus dem Turnstile-Abschnitt der iOS-SDK-Dokumentation in Ihr Projekt – ein kleines UIViewRepresentable um WKWebView, das Ihnen gehört.

4. Formular bauen

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

Als Parameter funktioniert jede Encodable-Struktur, sodass der Compiler die Feldnamen für Sie prüft. Netzwerkfehler und 5xx-Antworten werden mit einem einzigen Idempotenzschlüssel wiederholt – keine doppelten E-Mails bei wackliger Verbindung.

5. Testen

Starten Sie die App im Simulator oder auf einem Gerät, füllen Sie das Formular aus und tippen Sie auf Send. Die E-Mail landet in Ihrem Postfach und erscheint im Dashboard unter Verlauf.

  • origin_not_allowed – Mobile Apps erlauben ist ausgeschaltet oder nicht gespeichert.
  • captcha_required – noch kein Turnstile-Token; Send bleibt deaktiviert, bis die Prüfung abgeschlossen ist.
  • invalid_template_params – ein Pflichtfeld ist leer oder die E-Mail-Adresse ungültig.

Wenn Ihre Credits aufgebraucht sind, wird die Nachricht mit dem Status .held angenommen und nach dem Aufladen automatisch versendet – es geht nichts verloren.

Nächste Schritte

  • Bestätigen Sie dem Nutzer die Nachricht mit der Vorlage Automatische Antwort: Danke für Ihre Nachricht aus der Galerie.
  • Senden Sie SendOptions(locale: Locale.preferredLanguages.first), um eine Sprachvariante der Vorlage in der Sprache des Nutzers zu verwenden.
Alle Tutorials