포스트

How to send emails from iOS 14

With iOS 14, third-party app can be the default email app. This means we may have to support sending email with third-party apps. If the user is not using the default email app and use another app like gmail, we may need to handle to open gmail app to send email. Let’s see how to do this.

How to send email via default

Email composition Interface Email composition Interface

Apple’s MessageUI framework provides MFMailComposeViewController which shows an email composition interface to send email inside an app. Although this does not automatically send email, so the user need to tap themselves to send email. Here is the example code below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import MessageUI

class ViewController: UIViewController {

    ...

    func sendEmail() {
        let composer = MFMailComposeViewController()
        let receiver = "imjhk03@gmail.com"
        let subject = "Bug report: "
        let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] ?? 1.0    // App version
        let osVersion = UIDevice().systemVersion    // os version
        let message = """
        Hello,

        App Version: \(appVersion)
        iOS Version: \(osVersion)
        """
        
        if MFMailComposeViewController.canSendMail() {
            composerVC.mailComposeDelegate = self

            // Configure the fields of the interface.
            composerVC.setToRecipients([receiver])
            composerVC.setSubject(subject)
            composerVC.setMessageBody(message, isHTML: false)
            
            // Present the view controller modally.
            present(composer, animated: true, completion: nil)
        } else {
            // show failure alert
        }
    }

}

You need to import MessageUI and conform to MFMailComposeViewControllerDelegate protocol. Make sure to check if the user device can send email with canSendMail() function. Additionally, we can also get the app’s version or the device os version with Bundle or UIDevice.

To dismiss the email composition interface, we need to conform MFMailComposeViewControllerDelegate protocol. In mailComposeController(_:didFinishWith:error:) function we dismiss the view controller. We can also handle if the email has sent or cancelled to do more tasks.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// MARK: - MFMailComposeViewControllerDelegate
extension ViewController: MFMailComposeViewControllerDelegate {
    func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
        // Check the result or perform other tasks.
        if result == .sent {
            
        } else {
            
        }
        
        // Dismiss the mail compose view controller.
        controller.dismiss(animated: true)
    }
}


How to send email via third party apps

The other way to send email is to create URL with mailto scheme and open it. Below code shows the URL with Gmail, Microsoft Outlook, and Spark app.

1
2
3
4
5
6
let subjectEncoded = subject.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? subject
let bodyEncoded = body.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? body
        
let gmailUrl = URL(string: "googlegmail://co?to=\(receiver)&subject=\(subjectEncoded)&body=\(bodyEncoded)")
let outlookUrl = URL(string: "ms-outlook://compose?to=\(receiver)&subject=\(subjectEncoded)&body=\(bodyEncoded)")
let sparkUrl = URL(string: "readdle-spark://compose?recipient=\(receiver)&subject=\(subjectEncoded)&body=\(bodyEncoded)")

To open the URL, we need to set LSApplicationQueriesSchemes in the Info.plist.

1
2
3
4
5
6
<key>LSApplicationQueriesSchemes</key>
<array>
    <string>googlegmail</string>
    <string>ms-outlook</string>
    <string>readdle-spark</string>
</array>

We are going to use AlertSheet to show apps that can open the URL. By using the canOpenURL(_:) function, we check and filter the third party apps that the app can open. Then make a tuple to store the URL and the name.

1
2
3
4
5
6
7
8
let sendViaGmail = (url: gmailUrl, title: "Gmail")
let sendViaOutlook = (url: outlookUrl, title: "Outlook")
let sendViaSpark = (url: sparkUrl, title: "Spark")
        
let availableApps = [sendViaGmail, sendViaOutlook, sendViaSpark].filter { availableApp -> Bool in
    guard let url = availableApp.url else { return false }
    return UIApplication.shared.canOpenURL(url)
}

After selecting any apps from the AlertSheet, the open(_:options:completionHandler:) function will open the third party app to send email. If there are no apps that the app can open, we are going to show a failure alert.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
guard !availableApps.isEmpty else {
    presentAlertCanNotSendEmail()
    return
}
        
presentAlertSheetThirdPartyEmailApps(availableApps)

...
    
private func presentAlertCanNotSendEmail() {
    let alert = UIAlertController(title: "Alert", 
                                  message: "It seems there is no way to send email in your device. Please send email to bugReport@email.com", 
                                  preferredStyle: .alert)
    alert.addAction(UIAlertAction(title: "OK", style: .default))
    present(alert, animated: true)
}
    
private func presentAlertSheetThirdPartyEmailApps(_ availableApps: [AvailableApps]) {
    let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
    for app in availableApps {
        alert.addAction(UIAlertAction(title: app.title, style: .default, handler: { _ in
            guard let url = app.url else { return }
            UIApplication.shared.open(url, options: [:], completionHandler: nil)
        }))
    }
    alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
        
    present(alert, animated: true)
}

If you apply it, you can see the screenshot like below. Third Party App Alert Sheet and No available App Alert

WARNING: If you want to test sending an email app, you need to test it on a real device, not on an iOS simulator.

From iOS 14, third-party apps can be set as default email apps, and this post introduce how to support it. If you want to see the full code, check it on GitHub.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.