简体   繁体   English

如何从 Swift 打开邮件应用程序

[英]How to open mail app from Swift

Im working on a simple swift app where the user inputs an email address and presses a button which opens the mail app, with the entered address in the address bar.我正在开发一个简单的 swift 应用程序,用户在其中输入 email 地址并按下打开邮件应用程序的按钮,在地址栏中输入地址。 I know how to do this in Objective-C, but I'm having trouble getting it to work in Swift.我知道如何在 Objective-C 中执行此操作,但我无法让它在 Swift 中工作。

You can use simple mailto: links in iOS to open the mail app.您可以使用简单的 mailto: iOS 中的链接来打开邮件应用程序。

let email = "foo@bar.com"
if let url = URL(string: "mailto:\(email)") {
  if #available(iOS 10.0, *) {
    UIApplication.shared.open(url)
  } else {
    UIApplication.shared.openURL(url)
  }    
}

While other answers are all correct, you can never know if the iPhone/iPad that is running your application has the Apple's Mail app installed or not as it can be deleted by the user.虽然其他答案都是正确的,但您永远无法知道运行您的应用程序的 iPhone/iPad 是否安装了 Apple 的邮件应用程序,因为它可以被用户删除。

It is better to support multiple email clients.最好支持多个电子邮件客户端。 Following code handles the email sending in a more graceful way.以下代码以更优雅的方式处理电子邮件发送。 The flow of the code is:代码流程为:

  • If Mail app is installed, open Mail's composer pre-filled with provided data如果安装了 Mail 应用程序,请打开预先填充了提供数据的 Mail 的作曲家
  • Otherwise, try opening the Gmail app, then Outlook, then Yahoo mail, then Spark, in this order否则,请尝试依次打开 Gmail 应用程序、Outlook、Yahoo 邮件和 Spark
  • If none of those clients are installed, fallback to default mailto:.. that prompts the user to install Apple's Mail app.如果没有安装这些客户端,则回退到默认的mailto:..提示用户安装 Apple 的 Mail 应用程序。

Code is written in Swift 5 :代码是用Swift 5编写的:

    import MessageUI
    import UIKit

    class SendEmailViewController: UIViewController, MFMailComposeViewControllerDelegate {
        
        @IBAction func sendEmail(_ sender: UIButton) {
            // Modify following variables with your text / recipient
            let recipientEmail = "test@email.com"
            let subject = "Multi client email support"
            let body = "This code supports sending email via multiple different email apps on iOS! :)"
            
            // Show default mail composer
            if MFMailComposeViewController.canSendMail() {
                let mail = MFMailComposeViewController()
                mail.mailComposeDelegate = self
                mail.setToRecipients([recipientEmail])
                mail.setSubject(subject)
                mail.setMessageBody(body, isHTML: false)
                
                present(mail, animated: true)
            
            // Show third party email composer if default Mail app is not present
            } else if let emailUrl = createEmailUrl(to: recipientEmail, subject: subject, body: body) {
                UIApplication.shared.open(emailUrl)
            }
        }
        
        private func createEmailUrl(to: String, subject: String, body: String) -> URL? {
            let subjectEncoded = subject.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
            let bodyEncoded = body.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
            
            let gmailUrl = URL(string: "googlegmail://co?to=\(to)&subject=\(subjectEncoded)&body=\(bodyEncoded)")
            let outlookUrl = URL(string: "ms-outlook://compose?to=\(to)&subject=\(subjectEncoded)")
            let yahooMail = URL(string: "ymail://mail/compose?to=\(to)&subject=\(subjectEncoded)&body=\(bodyEncoded)")
            let sparkUrl = URL(string: "readdle-spark://compose?recipient=\(to)&subject=\(subjectEncoded)&body=\(bodyEncoded)")
            let defaultUrl = URL(string: "mailto:\(to)?subject=\(subjectEncoded)&body=\(bodyEncoded)")
            
            if let gmailUrl = gmailUrl, UIApplication.shared.canOpenURL(gmailUrl) {
                return gmailUrl
            } else if let outlookUrl = outlookUrl, UIApplication.shared.canOpenURL(outlookUrl) {
                return outlookUrl
            } else if let yahooMail = yahooMail, UIApplication.shared.canOpenURL(yahooMail) {
                return yahooMail
            } else if let sparkUrl = sparkUrl, UIApplication.shared.canOpenURL(sparkUrl) {
                return sparkUrl
            }
            
            return defaultUrl
        }
        
        func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
            controller.dismiss(animated: true)
        }
    }

Please note that I intentionally missed out the body for the Outlook app, as it is not able to parse it.请注意,我故意遗漏了 Outlook 应用程序的正文,因为它无法解析它。

You also have to add following code to Info.plist file that whitelists the URl query schemes that are used.您还必须将以下代码添加到将使用的 URl 查询方案列入白名单的Info.plist文件中。

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>googlegmail</string>
    <string>ms-outlook</string>
    <string>readdle-spark</string>
    <string>ymail</string>
</array>

I'm not sure if you want to switch to the mail app itself or just open and send an email.我不确定您是要切换到邮件应用程序本身还是只是打开并发送电子邮件。 For the latter option linked to a button IBAction:对于链接到按钮 IBAction 的后一个选项:

    import UIKit
    import MessageUI

    class ViewController: UIViewController, MFMailComposeViewControllerDelegate {

    @IBAction func launchEmail(sender: AnyObject) {

    var emailTitle = "Feedback"
    var messageBody = "Feature request or bug report?"
    var toRecipents = ["friend@stackoverflow.com"]
    var mc: MFMailComposeViewController = MFMailComposeViewController()
    mc.mailComposeDelegate = self
    mc.setSubject(emailTitle)
    mc.setMessageBody(messageBody, isHTML: false)
    mc.setToRecipients(toRecipents)

    self.presentViewController(mc, animated: true, completion: nil)
    }

    func mailComposeController(controller:MFMailComposeViewController, didFinishWithResult result:MFMailComposeResult, error:NSError) {
        switch result {
        case MFMailComposeResultCancelled:
            print("Mail cancelled")
        case MFMailComposeResultSaved:
            print("Mail saved")
        case MFMailComposeResultSent:
            print("Mail sent")
        case MFMailComposeResultFailed:
            print("Mail sent failure: \(error?.localizedDescription)")
        default:
            break
        }
        self.dismissViewControllerAnimated(true, completion: nil)
    }

    }

For Swift 4.2+ and iOS 9+适用于 Swift 4.2+ 和 iOS 9+

let appURL = URL(string: "mailto:test@example.com")!

if #available(iOS 10.0, *) {
    UIApplication.shared.open(appURL, options: [:], completionHandler: nil)
} else {
    UIApplication.shared.openURL(appURL)
}

Replace test@example.com with your desired email address.将 test@example.com 替换为您想要的电子邮件地址。

You can also include a subject field, a message , and multiple recipients in the To, Cc, and Bcc fields:您还可以在“收件人”、“抄送”和“密件抄送”字段中包含主题字段、消息多个收件人

mailto:foo@example.com?cc=bar@example.com&subject=Greetings%20from%20Cupertino!&body=Wish%20you%20were%20here!

In Swift 3 you make sure to add import MessageUI and needs conform to the MFMailComposeViewControllerDelegate protocol.在 Swift 3 中,您确保添加import MessageUI并且需要符合MFMailComposeViewControllerDelegate协议。

func sendEmail() {
  if MFMailComposeViewController.canSendMail() {
    let mail = MFMailComposeViewController()
    mail.mailComposeDelegate = self
    mail.setToRecipients(["ved.ios@yopmail.com"])
    mail.setMessageBody("<p>You're so awesome!</p>", isHTML: true)

    present(mail, animated: true)
  } else {
    // show failure alert
  }
}

Protocol:协议:

func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
  controller.dismiss(animated: true)
}

Swift 2, with availability check: Swift 2,带有可用性检查:

import MessageUI

if MFMailComposeViewController.canSendMail() {
    let mail = MFMailComposeViewController()
    mail.mailComposeDelegate = self
    mail.setToRecipients(["test@test.test"])
    mail.setSubject("Bla")
    mail.setMessageBody("<b>Blabla</b>", isHTML: true)
    presentViewController(mail, animated: true, completion: nil)
} else {
    print("Cannot send mail")
    // give feedback to the user
}


// MARK: - MFMailComposeViewControllerDelegate

func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
    switch result.rawValue {
    case MFMailComposeResultCancelled.rawValue:
        print("Cancelled")
    case MFMailComposeResultSaved.rawValue:
        print("Saved")
    case MFMailComposeResultSent.rawValue:
        print("Sent")
    case MFMailComposeResultFailed.rawValue:
        print("Error: \(error?.localizedDescription)")
    default:
        break
    }
    controller.dismissViewControllerAnimated(true, completion: nil)
}

Here how it looks for Swift 4:这里是 Swift 4 的样子:

import MessageUI

if MFMailComposeViewController.canSendMail() {
    let mail = MFMailComposeViewController()
    mail.mailComposeDelegate = self
    mail.setToRecipients(["test@test.test"])
    mail.setSubject("Bla")
    mail.setMessageBody("<b>Blabla</b>", isHTML: true)
    present(mail, animated: true, completion: nil)
} else {
    print("Cannot send mail")
    // give feedback to the user
}

func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
        switch result.rawValue {
        case MFMailComposeResult.cancelled.rawValue:
            print("Cancelled")
        case MFMailComposeResult.saved.rawValue:
            print("Saved")
        case MFMailComposeResult.sent.rawValue:
            print("Sent")
        case MFMailComposeResult.failed.rawValue:
            print("Error: \(String(describing: error?.localizedDescription))")
        default:
            break
        }
        controller.dismiss(animated: true, completion: nil)
    }

Updated answer from Stephen Groom for Swift 3 Stephen Groom 为 Swift 3 更新的答案

let email = "email@email.com"
let url = URL(string: "mailto:\(email)")
UIApplication.shared.openURL(url!)

Here's an update for Swift 4 if you're simply looking to open up the mail client via a URL :如果您只是想通过URL打开邮件客户端,这里是 Swift 4 的更新:

let email = "foo@bar.com"
if let url = URL(string: "mailto:\(email)") {
   UIApplication.shared.open(url, options: [:], completionHandler: nil)
}

This worked perfectly fine for me :)这对我来说非常好:)

This is a straight forward solution of 3 steps in Swift.这是 Swift 中 3 个步骤的直接解决方案。

import MessageUI

Add to conform the Delegate添加以符合委托

MFMailComposeViewControllerDelegate

And just create your method:只需创建您的方法:

    func sendEmail() {
    if MFMailComposeViewController.canSendMail() {
        let mail = MFMailComposeViewController()
        mail.mailComposeDelegate = self
        mail.setToRecipients(["support@mail.com"])
        mail.setSubject("Support App")
        mail.setMessageBody("<p>Send us your issue!</p>", isHTML: true)
        presentViewController(mail, animated: true, completion: nil)
    } else {
        // show failure alert
    }
}

func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
    controller.dismissViewControllerAnimated(true, completion: nil)
}

You should try sending with built-in mail composer, and if that fails, try with share:您应该尝试使用内置邮件编辑器发送,如果失败,请尝试使用共享:

func contactUs() {

    let email = "info@example.com" // insert your email here
    let subject = "your subject goes here"
    let bodyText = "your body text goes here"

    // https://developer.apple.com/documentation/messageui/mfmailcomposeviewcontroller
    if MFMailComposeViewController.canSendMail() {

        let mailComposerVC = MFMailComposeViewController()
        mailComposerVC.mailComposeDelegate = self as? MFMailComposeViewControllerDelegate

        mailComposerVC.setToRecipients([email])
        mailComposerVC.setSubject(subject)
        mailComposerVC.setMessageBody(bodyText, isHTML: false)

        self.present(mailComposerVC, animated: true, completion: nil)

    } else {
        print("Device not configured to send emails, trying with share ...")

        let coded = "mailto:\(email)?subject=\(subject)&body=\(bodyText)".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
        if let emailURL = URL(string: coded!) {
            if #available(iOS 10.0, *) {
                if UIApplication.shared.canOpenURL(emailURL) {
                    UIApplication.shared.open(emailURL, options: [:], completionHandler: { (result) in
                        if !result {
                            print("Unable to send email.")
                        }
                    })
                }
            }
            else {
                UIApplication.shared.openURL(emailURL as URL)
            }
        }
    }
}

For Swift 4.2 and above对于 Swift 4.2 及更高版本

let supportEmail = "abc@xyz.com"
if let emailURL = URL(string: "mailto:\(supportEmail)"), UIApplication.shared.canOpenURL(emailURL)
{
    UIApplication.shared.open(emailURL, options: [:], completionHandler: nil)
}

Give the user to choose many mail options(like iCloud, google, yahoo, Outlook.com - if no mail is pre-configured in his phone) to send email.让用户选择许多邮件选项(如 iCloud、谷歌、雅虎、Outlook.com - 如果他的手机中没有预先配置邮件)来发送电子邮件。

In the view controller from where you want your mail-app to open on the tap.在视图控制器中,您希望您的邮件应用程序可以在点击时打开。

  • At the top of the file do, import MessageUI .在文件顶部,导入 MessageUI
  • Put this function inside your Controller.将此功能放在您的控制器中。

     func showMailComposer(){ guard MFMailComposeViewController.canSendMail() else { return } let composer = MFMailComposeViewController() composer.mailComposeDelegate = self composer.setToRecipients(["abc@gmail.com"]) // email id of the recipient composer.setSubject("testing!!!") composer.setMessageBody("this is a test mail.", isHTML: false) present(composer, animated: true, completion: nil) }
  • Extend your View Controller and conform to the MFMailComposeViewControllerDelegate .扩展您的视图控制器并符合MFMailComposeViewControllerDelegate

  • Put this method and handle the failure, sending of your mails.把这个方法和处理失败,发送你的邮件。

     func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { if let _ = error { controller.dismiss(animated: true, completion: nil) return } controller.dismiss(animated: true, completion: nil) }
@IBAction func launchEmail(sender: AnyObject) {
 if if MFMailComposeViewController.canSendMail() {
   var emailTitle = "Feedback"
   var messageBody = "Feature request or bug report?"
   var toRecipents = ["friend@stackoverflow.com"]
   var mc: MFMailComposeViewController = MFMailComposeViewController()
   mc.mailComposeDelegate = self
   mc.setSubject(emailTitle)
   mc.setMessageBody(messageBody, isHTML: false)
   mc.setToRecipients(toRecipents)

   self.present(mc, animated: true, completion: nil)
 } else {
   // show failure alert
 }
}

func mailComposeController(controller:MFMailComposeViewController, didFinishWithResult result:MFMailComposeResult, error:NSError) {
    switch result {
    case .cancelled:
        print("Mail cancelled")
    case .saved:
        print("Mail saved")
    case .sent:
        print("Mail sent")
    case .failed:
        print("Mail sent failure: \(error?.localizedDescription)")
    default:
        break
    }
    self.dismiss(animated: true, completion: nil)
}

Note that not all users have their device configure to send emails, which is why we need to check the result of canSendMail() before trying to send.请注意,并非所有用户都将其设备配置为发送电子邮件,这就是为什么我们需要在尝试发送之前检查 canSendMail() 的结果。 Note also that you need to catch the didFinishWith callback in order to dismiss the mail window.另请注意,您需要捕获 didFinishWith 回调才能关闭邮件窗口。

For those of us still lagging behind on Swift 2.3 here is Gordon's answer in our syntax:对于我们这些在 Swift 2.3 上仍然落后的人,这里是 Gordon 在我们的语法中的回答:

let email = "foo@bar.com"
if let url = NSURL(string: "mailto:\(email)") {
   UIApplication.sharedApplication().openURL(url)
}

In my case I was just trying to open the mail app, without creating an email draft.就我而言,我只是试图打开邮件应用程序,而不创建电子邮件草稿。

In case someone is stumbling upon this question and is actually trying to do the same thing here is the code I used:如果有人偶然发现这个问题并且实际上正在尝试做同样的事情,这里是我使用的代码:

private var openMailAppButton: some View { 
        Button {
            if let emailUrl = mailAppUrl() {
                UIApplication.shared.open(emailUrl)
            }
        } label: {
            Text("OPEN MAIL APP")
        }
    }

private func mailAppUrl() -> URL? {
        let gmailUrl = URL(string: "googlegmail://")
        let outlookUrl = URL(string: "ms-outlook://")
        let yahooMail = URL(string: "ymail://")
        let sparkUrl = URL(string: "readdle-spark://")
        let defaultUrl = URL(string: "message://")
        
        if let defaultUrl = defaultUrl, UIApplication.shared.canOpenURL(defaultUrl) {
            return defaultUrl
        } else if let gmailUrl = gmailUrl, UIApplication.shared.canOpenURL(gmailUrl) {
            return gmailUrl
        } else if let outlookUrl = outlookUrl, UIApplication.shared.canOpenURL(outlookUrl) {
            return outlookUrl
        } else if let yahooMail = yahooMail, UIApplication.shared.canOpenURL(yahooMail) {
            return yahooMail
        } else if let sparkUrl = sparkUrl, UIApplication.shared.canOpenURL(sparkUrl) {
            return sparkUrl
        }
        
        return defaultUrl
    }

I created a Swift package that handles exactly this and also implements a check if they have multiple email clients.我创建了一个 Swift 包来处理这个问题,并且还实现了检查他们是否有多个电子邮件客户端。

https://github.com/joe-scotto/EmailLink https://github.com/joe-scoto/EmailLink

func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult,error: Swift.Error?) { func mailComposeController(_ controller:MFMailComposeViewController,didFinishWith 结果:MFMailComposeResult,错误:Swift.Error?){

    controller.dismiss(animated: true, completion: nil)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM