Search code examples
iosswiftemailswiftuimessage

SwiftUI: Send email using MFMailComposeViewController


I am currently trying to implement a "send email" button in my SwiftUI app, using SwiftUI lifecycle and targeting iOS 14.

I know there are quite some solutions presented online - here on stack overflow and elsewhere. However, I have-not been able to make anything work so far in simulator/on device.

My current solution looks like this (based on this question on stackoverflow:

import SwiftUI
import MessageUI
import Foundation

struct ContentView: View {

    class MailComposeViewController: UIViewController, MFMailComposeViewControllerDelegate {
    
        static let shared = MailComposeViewController()
    
        func sendEmail() {
            if MFMailComposeViewController.canSendMail() {
                let mail = MFMailComposeViewController()
                mail.mailComposeDelegate = self
                mail.setToRecipients(["test@test.com"])

                UIApplication.shared.windows.last?.rootViewController?.present(mail, animated: true, completion: nil)
            } else {
                // Alert
            }
        }
    
        func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
            controller.dismiss(animated: true, completion: nil)
        }
    }
    
    var body: some View {
        Button(action: {
            MailComposeViewController.shared.sendEmail()
        }, label: {
            Text("Send")
        })
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

The simulator does show the button and doesn't give me any errors. However, upon clicking the button, nothing happens at all - same thing when testing on device.

Any idea what might be wrong here?

Thanks!


Solution

  • Building up on the code snippet shared in my original question:

    Based on the answer from @Arjun this is my current workaround to account for the edge case that someone might have deleted the Apple Mail app and is using another email app:

    Button(action: {
        if MailComposeViewController.shared.canSendMail() {
            MailComposeViewController.shared.sendEmail()
        } else {
            openURL(URL(string: "mailto:someone@example.com?subject=This%20is%20the%20subject")!)
        }
    }, label: {
        Text("Send")
    })
    

    It opens the in-app sheet as long as the user has set up apple mail and otherwise switches to any other email app using a mailto: link.