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(["[email protected]"])
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!
Your code works fine, the problem is that the iOS Simulator does not have the Mail app, thus MFMailComposeViewController.canSendMail() returns false. Try it on a physical device, it works. The reason you didn't see any errors is because of this block of code:
if MFMailComposeViewController.canSendMail() {
let mail = MFMailComposeViewController()
mail.mailComposeDelegate = self
mail.setToRecipients(["[email protected]"])
UIApplication.shared.windows.last?.rootViewController?.present(mail, animated: true, completion: nil)
} else {
// Alert
}
Inside the else block, instead of temporarily commenting // Alert, you should print something instead while debugging, it'll make your life a lot easier.
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:[email protected]?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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With