Cách mở ứng dụng thư từ Swift


119

Tôi đang làm việc trên một ứng dụng nhanh đơn giản trong đó người dùng nhập địa chỉ email và nhấn một nút mở ứng dụng thư với địa chỉ đã nhập trong thanh địa chỉ. Tôi biết cách thực hiện điều này trong Objective-C, nhưng tôi gặp khó khăn khi làm việc trong Swift.

Câu trả lời:


240

Bạn có thể sử dụng các liên kết mailto: đơn giản trong iOS để mở ứng dụng thư.

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
Có lẽ đáng để nói thêm rằng điều này không hoạt động trong trình mô phỏng, chỉ trên thiết bị ... Xem stackoverflow.com/questions/26052815/…
Pieter

4
bây giờ bạn cần thêm "!" trong dòng thứ hai, cho NSURL NSURL (chuỗi: "mailto: (email)")!
anthonyqz

4
tại sao nó nói điều này chỉ có trên ios 10 hoặc mới hơn khi câu trả lời rõ ràng là 3 năm tuổi
pete

1
Ví dụ về Swift 4 / iOS 10+: UIApplication.shared.open (url, options: [:], completeHandler: nil) Chuyển một từ điển trống cho các tùy chọn sẽ tạo ra kết quả giống như cách gọi openURL đã làm.
Luca Ventura

Cảm ơn ... Nó sẽ giúp rất nhiều :) :)
Anjali jariwala

60

Mặc dù các câu trả lời khác đều đúng, nhưng bạn không bao giờ có thể biết được iPhone / iPad đang chạy ứng dụng của mình có cài đặt ứng dụng Mail của Apple hay không vì người dùng có thể xóa ứng dụng này.

Sẽ tốt hơn nếu hỗ trợ nhiều ứng dụng email. Đoạn mã sau xử lý việc gửi email theo cách dễ dàng hơn. Luồng của mã là:

  • Nếu ứng dụng Thư được cài đặt, hãy mở trình soạn thư của Thư được điền sẵn với dữ liệu được cung cấp
  • Nếu không, hãy thử mở ứng dụng Gmail, rồi đến Outlook, rồi Yahoo mail, rồi Spark, theo thứ tự này
  • Nếu không có ứng dụng khách nào được cài đặt, dự phòng về mặc định mailto:..sẽ nhắc người dùng cài đặt ứng dụng Thư của Apple.

Mã được viết bằng 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)
        }
    }

Xin lưu ý rằng tôi đã cố tình bỏ sót phần nội dung cho ứng dụng Outlook, vì nó không thể phân tích cú pháp.

Bạn cũng phải thêm mã sau vào Info.plisttệp danh sách trắng các lược đồ truy vấn URl được sử dụng.

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

4
Làm tốt. Đây là câu trả lời đầy đủ nhất và có thể dễ dàng mở rộng cho các ứng dụng email khách khác. IMHO, tôi không nghĩ là có thể chấp nhận được vào cuối năm 2019 nếu chỉ nói với người đó "xin lỗi, bạn không gặp may" nếu họ không sử dụng ứng dụng Apple Mail mặc định, như hầu hết các giải pháp khác đề xuất. Điều này khắc phục sự thiếu hụt đó.
wildcat

Phương pháp này có hoạt động với HTML không? Tôi không thể hiển thị nó đúng cách.
Matthew Bradshaw

@MatthewBradshaw, bạn có thể hỗ trợ HTML cho trình soạn thư mặc định bằng cách đặt isHTMLtrong đoạn mã trên thành true. Đối với các ứng dụng khách khác, điều này dường như không thể thực hiện được, để đọc thêm, hãy xem stackoverflow.com/questions/5620324/mailto-link-with-html-body
WebMajstr

1
Cảm ơn, chảo này tuyệt vời. Tôi đã sửa đổi một chút để cho phép người dùng chọn ứng dụng khách ưa thích của họ (tôi đang lọc trước chúng với canOpenUrl). Btw body cho Microsoft Outlook đang hoạt động tốt :-)
Filip

Điều này là tuyệt vời! Có ai đã làm điều này cho SwiftUI?
Averett

55

Tôi không chắc liệu bạn có muốn chuyển sang ứng dụng thư hay chỉ cần mở và gửi email. Đối với tùy chọn sau được liên kết với IBAction nút:

    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
Tôi đang gặp sự cố trong đó hàm đại biểu mailComposeController không được gọi.
AustinT

3
Thêm "import MessageUI" vào phần nhập của bạn và đảm bảo thêm tùy chọn "MFMailComposeViewControllerDelegate" vào khai báo lớp của bạn như: class myClass: UIViewController, MFMailComposeViewControllerDelegate {
Jalakoo 21/02/15

MFMailComposeViewController () trả về con số không cho tôi
ilan

2
Cũng có vấn đề: 'NSInvalidArgumentException', reason: 'Application tried to present a nil modal view controller on target. App treo trong một số thiết bị (iPhone 5, iPhone 6 và iPad Mini)
Spacemonkey

23

Trong Swift 3, bạn đảm bảo thêm import MessageUIvà cần tuân thủ MFMailComposeViewControllerDelegategiao thức.

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

Giao thức:

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

16

Swift 2, với kiểm tra tính khả dụng :

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

Đối với Swift 4.2+ và 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)
}

Thay thế TEST@EXAMPLE.COM bằng địa chỉ email mong muốn của bạn.


15

Đây là cách nó trông như thế nào cho 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

Câu trả lời cập nhật từ Stephen Groom cho Swift 3

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

10

Đây là bản cập nhật cho Swift 4 nếu bạn chỉ đơn giản là muốn mở ứng dụng thư khách thông qua URL:

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

Điều này hoàn toàn tốt cho tôi :)


9

Đây là giải pháp chuyển tiếp 3 bước trong Swift.

import MessageUI

Thêm để phù hợp với Ủy quyền

MFMailComposeViewControllerDelegate

Và chỉ cần tạo phương pháp của bạn:

    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

Bạn nên thử gửi bằng trình soạn thư tích hợp sẵn và nếu không thành công, hãy thử với chia sẻ:

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

lỗi: "Ứng dụng này không được phép truy vấn cho lược đồ 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)
}

Lưu ý rằng không phải tất cả người dùng đều có cấu hình thiết bị của họ để gửi email, đó là lý do tại sao chúng ta cần kiểm tra kết quả của canSendMail () trước khi cố gắng gửi. Cũng lưu ý rằng bạn cần bắt gọi lại didFinishWith để loại bỏ cửa sổ thư.


1

Trong bộ điều khiển chế độ xem từ nơi bạn muốn ứng dụng thư của mình mở khi nhấn.

  • Ở đầu tệp, nhập MessageUI .
  • Đặt chức năng này bên trong Bộ điều khiển của bạn.

    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)
     }
  • Mở rộng View Controller của bạn và tuân theo MFMailComposeViewControllerDelegate .

  • Đặt phương pháp này và xử lý lỗi gửi thư của bạn.

    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

Đối với những người trong chúng ta vẫn còn tụt hậu trên Swift 2.3, đây là câu trả lời của Gordon trong cú pháp của chúng tôi:

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

0

Đối với Swift 4.2 trở lên

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

Cung cấp cho người dùng nhiều tùy chọn thư (như iCloud, google, yahoo, Outlook.com - nếu không có thư nào được cấu hình sẵn trong điện thoại của họ) để gửi email.


1
Trong trường hợp của tôi, với iOS 13, khi gọi UIApplication.shared.open, hệ điều hành sẽ luôn hiển thị hộp thoại đề nghị cài đặt Mail.app (oh, và canOpenURL cho "mailto" cũng luôn đúng), ngay cả khi có ứng dụng thư. Vì vậy, điều này chắc chắn không thành công.
NeverwinterMoon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.