如何从Swift打开邮件应用


118

我正在开发一个简单的快捷应用程序,在该应用程序中,用户输入了电子邮件地址,然后按下了一个按钮,打开了邮件应用程序,地址栏中输入了该地址。我知道如何在Objective-C中做到这一点,但是我很难让它在Swift中工作。

Answers:


240

您可以使用iOS中的简单mailto:链接打开邮件应用程序。

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)
  }    
}

77
也许值得补充一下,这在模拟器中仅在设备上不起作用...请参见stackoverflow.com/questions/26052815/…–
Pieter

4
现在您需要添加“!” 在第二行中,输入NSURL NSURL(string:“ mailto:(email)”)!
anthonyqz 2015年

4
为什么说答案只有3岁,才在ios 10或更高版本上提供此功能
皮特

1
Swift 4 / iOS 10+示例:UIApplication.shared.open(url,options:[:],completionHandler:nil)为选项传递一个空字典会产生与调用openURL相同的结果。
卡·文图拉

谢谢...这有很大帮助:) :)
Anjali jariwala 18'27

60

尽管其他答案都正确,但您永远无法知道运行应用程序的iPhone / iPad是否安装了Apple的Mail应用程序,因为用户可以删除它。

最好支持多个电子邮件客户端。下面的代码以更优雅的方式处理电子邮件发送。代码流为:

  • 如果已安装Mail应用程序,请打开Mail的编辑器,并预先填充提供的数据
  • 否则,请尝试依次打开Gmail应用,Outlook,Yahoo邮件和Spark。
  • 如果未安装这些客户端,则回退为默认值mailto:..,提示用户安装Apple的Mail应用程序。

代码是用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: .urlHostAllowed)!
            let bodyEncoded = body.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!

            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)
        }
    }

请注意,我故意错过了Outlook应用的正文,因为它无法解析它。

您还必须向Info.plist文件添加以下代码,该文件将使用的UR1查询方案列入白名单。

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

4
做得好。这是最完整的答案,可以很容易地扩展到其他电子邮件客户端应用程序。恕我直言,我认为在2019年末仅仅告诉对方“抱歉,您不走运”,如果他们没有使用默认的Apple Mail应用程序是不可接受的,正如大多数其他解决方案所建议的那样。这样可以解决该缺陷。
wildcat12

此方法适用于HTML吗?我无法正确显示它。
马修·布拉德肖

@MatthewBradshaw,您可以通过将isHTML上面的代码设置为true 来支持默认邮件编写器的HTML 。对于其他客户端,似乎没有可能,有关更多阅读,请参阅stackoverflow.com/questions/5620324/mailto-link-with-html-body
WebMajstr

1
谢谢,这锅好极了。我对其进行了少许修改,以使用户可以选择自己喜欢的客户端(我先使用canOpenUrl对其进行过滤)。Microsoft Outlook的Btw主体运行正常:-)
Filip

这太棒了!有人为SwiftUI做过此事吗?
Averett

55

我不确定是要切换到邮件应用程序本身还是只是打开并发送电子邮件。对于链接到按钮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)
    }

    }

1
我遇到未调用mailComposeController委托函数的问题。
奥斯丁,2015年

3
将“ import MessageUI”添加到您的导入中,并确保将“ MFMailComposeViewControllerDelegate”选项添加到您的类声明中,例如: class myClass: UIViewController, MFMailComposeViewControllerDelegate {
Jalakoo 2015年

MFMailComposeViewController()为我返回nil
ilan 2015年

2
也有问题:'NSInvalidArgumentException', reason: 'Application tried to present a nil modal view controller on target。应用在某些设备(iPhone 5,iPhone 6和iPad Mini)上
崩溃

23

在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
  }
}

协议:

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

16

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)
}

16

对于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)
}

将TEST@EXAMPLE.COM替换为所需的电子邮件地址。


15

这是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)
    }

12

Stephen Groom针对Swift 3的更新答案

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

10

如果您只是想通过以下方式打开邮件客户端,这是Swift 4的更新URL

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

这对我来说非常好:)


9

这是Swift中3个步骤的直接解决方案。

import MessageUI

添加以符合委托

MFMailComposeViewControllerDelegate

只需创建您的方法:

    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)
}

4

您应该尝试使用内置邮件编辑器进行发送,如果失败,请尝试使用共享:

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)
            }
        }
    }
}

错误:“不允许该应用查询方案mailto”
Khushal iOS

3
@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)
}

请注意,并非所有用户都将其设备配置为发送电子邮件,这就是为什么我们需要在尝试发送之前检查canSendMail()的结果。还要注意,您需要捕获didFinishWith回调才能关闭邮件窗口。


1

在视图控制器中,您希望从中打开邮件应用的位置。

  • 在文件顶部,导入MessageUI
  • 将此功能放入控制器中。

    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)
     }
  • 扩展您的View Controller并遵循MFMailComposeViewControllerDelegate

  • 使用此方法并处理失败,发送邮件。

    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)
    }

0

对于仍然落后于Swift 2.3的我们来说,这是Gordon在我们的语法中的答案:

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

0

对于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)
}

给用户选择许多邮件选项(例如iCloud,google,yahoo,Outlook.com-如果手机中未预先配置邮件)来发送电子邮件。


1
就我而言,在iOS 13中,调用UIApplication.shared.open时,操作系统将始终显示一个对话框,提示您安装Mail.app(哦,“ mailto”的canOpenURL也始终为true),即使还有其他情况也是如此。邮件应用程序。因此,这绝对无法解决。
NeverwinterMoon,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.