【问题标题】:How to open mail app from Swift如何从 Swift 打开邮件应用程序
【发布时间】:2014-11-16 20:27:40
【问题描述】:

我正在开发一个简单的 swift 应用程序,用户输入一个电子邮件地址并按下一个打开邮件应用程序的按钮,在地址栏中输入地址。我知道如何在 Objective-C 中做到这一点,但我无法让它在 Swift 中工作。

【问题讨论】:

    标签: ios swift


    【解决方案1】:

    适用于 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 替换为您想要的电子邮件地址。

    您还可以在“收件人”、“抄送”和“密件抄送”字段中包含主题字段、消息和多个收件人:

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

    【讨论】:

    • 可以这样预定义邮件的主题吗?
    【解决方案2】:

    虽然其他答案都是正确的,您永远无法知道运行您的应用程序的 iPhone/iPad 是否安装了 Apple 的邮件应用程序,因为它可以被用户删除。 p>

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

    • 如果安装了 Mail 应用程序,请打开 Mail 的 Composer,其中预先填充了提供的数据
    • 否则,请尝试依次打开 Gmail 应用、Outlook、Yahoo 邮件和 Spark
    • 如果没有安装这些客户端,则回退到默认的mailto:..,提示用户安装 Apple 的邮件应用程序。

    代码是用 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)
            }
        }
    

    请注意,我故意遗漏了 Outlook 应用程序的正文,因为它无法解析它。

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

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

    【讨论】:

    • 干得好。这是最完整的答案,并且很容易扩展到其他电子邮件客户端应用程序。恕我直言,我认为在 2019 年末,如果他们不使用默认的 Apple Mail 应用程序,就像大多数其他解决方案所建议的那样,只告诉对方“对不起,你不走运”是不可接受的。这解决了这个缺陷。
    • 此方法是否适用于 HTML?我无法正常显示。
    • @MatthewBradshaw 您可以通过将上述代码中的 isHTML 设置为 true 来支持默认邮件编写器的 HTML。对于其他客户,这似乎是不可能的,进一步阅读请参阅stackoverflow.com/questions/5620324/mailto-link-with-html-body
    • 谢谢,这个炒锅很棒。我稍微修改了一下,让用户选择他们喜欢的客户端(我提前用 canOpenUrl 过滤它们)。顺便说一句,Microsoft Outlook 的主体工作正常 :-)
    • 我认为,应该是 .urlQueryAllowed 而不是 .urlHostAllowed
    【解决方案3】:

    在视图控制器中,您希望通过点击打开邮件应用程序。

    • 在文件顶部,import 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)
       }
      
    • 扩展您的视图控制器并符合 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)
      }
      

    【讨论】:

      【解决方案4】:

      适用于 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、谷歌、雅虎、Outlook.com - 如果他的手机中没有预先配置邮件)来发送电子邮件。

      【讨论】:

      • 在我的情况下,在 iOS 13 中,当调用 UIApplication.shared.open 时,操作系统总是会显示一个对话框来安装 Mail.app(哦,“mailto”的 canOpenURL 总是正确的,太),即使有其他邮件应用程序。所以这绝对行不通。
      【解决方案5】:

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

      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”
      • @KhushaliOS 使用真机代替模拟器
      【解决方案6】:

      如果您只是想通过URL 打开邮件客户端,这里有 Swift 4 的更新:

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

      这对我来说非常好:)

      【讨论】:

        【解决方案7】:

        您可以在 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)
          }    
        }
        

        【讨论】:

        • 也许值得补充的是,这在模拟器中不起作用,只能在设备上......见stackoverflow.com/questions/26052815/…
        • 现在您需要添加“!”在第二行,对于 NSURL NSURL(string: "mailto:(email)")!
        • 为什么它说这仅在 ios 10 或更高版本上可用,而答案显然是 3 岁了
        • Swift 4/iOS 10+ 示例:UIApplication.shared.open(url, options: [:], completionHandler: nil) 为选项传递一个空字典会产生与调用 openURL 相同的结果。
        • 您还可以提供主题、正文等。见developer.apple.com/library/archive/featuredarticles/…
        【解决方案8】:

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

        【讨论】:

          【解决方案9】:

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

          【讨论】:

            【解决方案10】:
            @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 回调才能关闭邮件窗口。

            【讨论】:

              【解决方案11】:

              对于我们这些在 Swift 2.3 上仍然落后的人,这里是 Gordon 在我们的语法中的回答:

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

              【讨论】:

                【解决方案12】:

                Stephen Groom 为 Swift 3 更新的答案

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

                【讨论】:

                  【解决方案13】:

                  Swift 2,带有availability 检查:

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

                  【讨论】:

                    【解决方案14】:

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

                    【讨论】:

                      【解决方案15】:

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

                      【讨论】:

                      • 我遇到了未调用 mailComposeController 委托函数的问题。
                      • 将“import MessageUI”添加到您的导入中,并确保将“MFMailComposeViewControllerDelegate”选项添加到您的类声明中,例如:class myClass: UIViewController, MFMailComposeViewControllerDelegate {
                      • MFMailComposeViewController() 为我返回 nil
                      • 也有问题:'NSInvalidArgumentException', reason: 'Application tried to present a nil modal view controller on target。应用程序在某些设备(iPhone 5、iPhone 6 和 iPad Mini)中崩溃
                      猜你喜欢
                      • 2017-02-10
                      • 1970-01-01
                      • 2015-11-02
                      • 2018-03-20
                      • 1970-01-01
                      • 2012-05-17
                      • 1970-01-01
                      • 2015-06-23
                      • 1970-01-01
                      相关资源
                      最近更新 更多