Appointment booking feature in my app

Hey everyone,

I am building an app for my dad's business and I have implemented a feature where you can book a consultation with him. You can select a date, enter your name and your email and a note if you'd like. And when you press "Book", it sends an email to my dad with all of the info that you inputted.

That all works well, but when you select the "Book" button, the mail composer pops up with the appointment info that you inputted. But I would like for the email to automatically send to my dad when the user presses "Book", I don't want the user to have to send the email along with pressing the "Book" button.

Is this possible? And if not, what are some other ways that I can implement the appointment booking software?

Any help would be appreciated! Thanks in advance.

Here is the code for the booking page:

import UIKit
import MessageUI
struct AppointmentFormView: View {
    @State private var name: String = ""
    @State private var contact: String = ""
    @State private var selectedDate = Date()
    @State private var notes: String = ""
    @State private var showAlert = false
    
    var body: some View {
        Form {
            Section(header: Text("Personal Information")) {
                TextField("First + Last Name", text: $name)
                TextField("Your Email Address", text: $contact)
            }
            
            Section(header: Text("Appointment Details")) {
                DatePicker("When would you like your appointment?", selection: $selectedDate, displayedComponents: [.date])
                TextField("Anything you'd like us to know?", text: $notes)
            }
            
            Button(action: {
                // Perform validation and backend tasks
                bookAppointment()
            }) {
                Text("Book")
            }
        }
        .alert(isPresented: $showAlert) {
            Alert(title: Text("Appointment Booked"), message: Text("Your appointment has been successfully booked."), dismissButton: .default(Text("OK")))
        }
    }
    
    private func bookAppointment() {
        // Perform validation and backend tasks here
        // Example implementation: show alert when appointment is booked
        showAlert = true
        
        // Compose and send the email notification
        let mailView = MailView(recipientEmail: "inquiries@metricacarpentry.com",
                                subject: "New Appointment Booked",
                                messageBody: """
                                Name: \(name)
                                Contact: \(contact)
                                Date: \(selectedDate)
                                Notes: \(notes)
                                """)
        UIApplication.shared.windows.first?.rootViewController?.present(UIHostingController(rootView: mailView), animated: true, completion: nil)
    }
}

struct UIMailView: UIViewControllerRepresentable {
    let recipientEmail: String
    let subject: String
    let messageBody: String
    @Binding var showAlert: Bool // Add showAlert binding
    
    func makeUIViewController(context: Context) -> MFMailComposeViewController {
        let composeVC = MFMailComposeViewController()
        composeVC.mailComposeDelegate = context.coordinator
        composeVC.setToRecipients([recipientEmail])
        composeVC.setSubject(subject)
        composeVC.setMessageBody(messageBody, isHTML: false)
        return composeVC
    }
    
    func updateUIViewController(_ uiViewController: MFMailComposeViewController, context: Context) {
        // No need to update the view controller
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(showAlert: $showAlert) // Pass showAlert binding to Coordinator
    }
    final class Coordinator: NSObject, MFMailComposeViewControllerDelegate {
        @Binding var showAlert: Bool
        
        init(showAlert: Binding<Bool>) {
            _showAlert = showAlert
        }
        
        func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
            EmailHelper.getRootViewController()?.dismiss(animated: true, completion: nil)
            
            if result == .sent {
                let alert = UIAlertController(title: "Email Sent ✅", message: "Thanks for your inquiry! We'll get back to you within 24 hours.", preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
                EmailHelper.getRootViewController()?.present(alert, animated: true, completion: nil)
            }
        }
        }
    }

Replies

I don't think it's possible to do this in the app, probably because of a privacy and spam reduction policy. Imagine if any app could randomly just post emails with your data in without your knowledge. The mail sheet appears so you know that you're about to send an email.

However, you can do this if you have your own server. I'm guessing your Dad has a website for his business? You can write a script that sits on the server, and receives data that your app sends, then sends the email itself using the server's mail app. Something like this:

    @IBAction func sendConsultationRequest(_ sender: AnyObject) {
        DispatchQueue.main.async {
            // Disable the UI, show an activity spinner
            self.activitySpinner.isHidden = false
            self.activitySpinner.startAnimating()
        }

        // Craft the url to call
        let url: URL = URL(string: "https://www.website.com/app/sendmessage.php")!
        let request: NSMutableURLRequest = NSMutableURLRequest(url: url)
        request.httpMethod = "POST"

        // Craft the parameters that are going to be sent to the server script
        let params = ["message": messageField.text!, "customerName": customerName.text!, "customerEmail": customerEmail.text!] as Dictionary<String, String>

        request.httpBody = try! JSONSerialization.data(withJSONObject: params, options: [])
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.addValue("application/json", forHTTPHeaderField: "Accept")

        // Call the script, and then re-enable the UI, stop the activity spinner etc.
        URLSession.shared.dataTask(with: request as URLRequest) {data, response, err in
            DispatchQueue.main.async {
                self.activitySpinner.stopAnimating()
                self.dismiss(animated: true) { () -> Void in }
            }
        }.resume()
    }

And the script on the server should be something like this (PHP):

<?php
    $handle = fopen('php://input','r');
    $jsonInput = fgets($handle);
    $decoded = json_decode($jsonInput, true);

    $to =      'dad@website.com';
    $subject = 'Consultation request';
    $body =    'From: ' . $decoded['customerName'] . "\r\n" .
               'Email: ' . $decoded['customerEmail'] . "\r\n" .
               'Message: ' . $decoded['message'];
    $headers = 'From: app@website.com' . "\r\n" .
               'Reply-To: app@website.com' . "\r\n" . // You can change this to the customer's email if you want your Dad to be able to reply directly to them
               'X-Mailer: PHP/' . phpversion();

    mail($to, $subject, $body, $headers);
?>