Zum Inhalt springen

Anfrageformular in iOS mit SwiftUI erstellen – Angebotsanfrage per E-Mail

Ein SwiftUI-Anfrageformular mit Auswahl von Leistung und Budget sowie Termin, das Ihnen jede Anfrage per E-Mail schickt und dem Kunden automatisch eine Bestätigung sendet – ohne Backend.

Aktualisiert:

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

In diesem Tutorial bauen Sie ein Formular für Angebotsanfragen in SwiftUI mit nativen Pickern: Leistung, Budget und Termin, dazu eine Beschreibung. Sie erhalten eine strukturierte E-Mail, der Kunde eine automatische Bestätigung.

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

1. Postfach verbinden und Vorlagen anlegen

  1. E-Mail-Dienste → Dienst hinzufügen: Verbinden Sie Ihr Postfach oder Ihren Anbieter, Als Standard festlegen, Prüfen & speichern.
  2. Vorlagen → Aus der Galerie → Angebotsanfrage (Kategorie Geschäftlich) → Vorlage verwenden.
  3. Aus der Galerie → Automatische Antwort: Danke für Ihre Nachricht → Vorlage verwenden; Standardwerte für company_name und response_time festlegen und die Vorlage dann in der Anfragevorlage unter Einstellungen → Zustellung → Vorlage für automatische Antwort auswählen.

Die Anfragevorlage braucht name, email, service und details; phone, company, budget und deadline (YYYY-MM-DD) sind optional. service und budget akzeptieren nur die Werte auf dem Tab Parameter – verwenden Sie in der App dieselben Zeichenketten. Das Codebeispiel nutzt die Werte der englischen Vorlage; eine auf Deutsch angelegte Vorlage hat Website, Onlineshop, Mobile App, Beratung, Sonstiges und Unter 5.000 €, 5.000–20.000 €, 20.000–50.000 €, Über 50.000 €.

2. Mobile Apps erlauben und CAPTCHA aktivieren

  • Sicherheit → Mobile Apps → Mobile Apps erlauben → Speichern.
  • Anfragevorlage → Einstellungen → Schutz → CAPTCHA verlangen (Turnstile) – das gemeinsame mobile Widget von Frontmail, keine Schlüssel nötig.

3. Paket hinzufügen

File → Add Package Dependencies… → https://github.com/frontmail-dev/frontmail-swift → Frontmail Ihrem Target hinzufügen, dann TurnstileView aus dem Turnstile-Abschnitt der iOS-SDK-Dokumentation kopieren.

4. Formular bauen

import SwiftUI
import Frontmail

let frontmail = try! Frontmail(publicKey: "pk_…")

let services = ["Website", "E-shop", "Mobile app", "Consulting", "Other"]
let budgets = ["Under $5k", "$5k–20k", "$20k–50k", "Over $50k"]

struct QuoteRequest: Encodable {
    let name: String
    let email: String
    let service: String
    let budget: String?   // nil is left out of the email
    let deadline: String? // YYYY-MM-DD
    let details: String
}

struct QuoteView: View {
    @State private var name = ""
    @State private var email = ""
    @State private var service = services[0]
    @State private var budget = ""
    @State private var hasDeadline = false
    @State private var deadline = Date()
    @State private var details = ""
    @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 {
            Section {
                TextField("Name", text: $name)
                TextField("Email", text: $email)
                    .keyboardType(.emailAddress)
                    .textInputAutocapitalization(.never)
            }
            Section {
                Picker("What do you need?", selection: $service) {
                    ForEach(services, id: \.self) { Text($0) }
                }
                Picker("Budget", selection: $budget) {
                    Text("Not sure yet").tag("")
                    ForEach(budgets, id: \.self) { Text($0) }
                }
                Toggle("I have a deadline", isOn: $hasDeadline)
                if hasDeadline {
                    DatePicker("Deadline", selection: $deadline, in: Date()..., displayedComponents: .date)
                }
                TextField("Project details", text: $details, 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("Request a quote") { 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
        let request = QuoteRequest(
            name: name,
            email: email,
            service: service,
            budget: budget.isEmpty ? nil : budget,
            deadline: hasDeadline ? deadline.formatted(Date.ISO8601FormatStyle(timeZone: .current).year().month().day()) : nil,
            details: details
        )
        do {
            _ = try await frontmail.send(
                templateID: "tpl_…",
                params: request,
                options: SendOptions(turnstileToken: token, turnstileKey: widget.turnstileKey)
            )
            info = "Thanks! We’ve emailed you a confirmation."
        } catch let error as FrontmailError {
            info = error.message
        } catch {
            info = error.localizedDescription
        }
    }
}

Optionale Eigenschaften mit dem Wert nil werden gar nicht kodiert, leere Zeilen tauchen in der E-Mail also nie auf.

5. Testen

Senden Sie eine Anfrage mit Ihrer eigenen Adresse als Kunden-E-Mail: Sie erhalten die Anfrage und die Bestätigung, und beide erscheinen im Verlauf.

Eine Anfrage mit Bestätigung kostet zwei Credits. Gehen die Credits aus, werden Anfragen als .held angenommen und nach dem Aufladen automatisch versendet.

Nächste Schritte

  • Aktivieren Sie Kontakte sammeln in den Einstellungen der Vorlage, um eine Liste aller Interessenten aufzubauen.
  • Hängen Sie ein Briefing oder Fotos an mit SendOptions(attachments: [.data(…)]) – siehe SDK-Dokumentation.
Alle Tutorials