วิธีเปิดแอพเมลจาก Swift


119

ฉันกำลังทำงานกับแอปพลิเคชันที่รวดเร็วที่ผู้ใช้ป้อนที่อยู่อีเมลและกดปุ่มเพื่อเปิดแอปอีเมลพร้อมที่อยู่ที่ป้อนในแถบที่อยู่ ฉันรู้วิธีทำใน Objective-C แต่ฉันมีปัญหาในการทำให้มันทำงานใน Swift

คำตอบ:


241

คุณสามารถใช้ลิงก์ 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)
  }    
}

77
อาจจะคุ้มค่าที่จะเพิ่มว่าสิ่งนี้ใช้ไม่ได้ในเครื่องจำลองเฉพาะบนอุปกรณ์เท่านั้น ... ดูstackoverflow.com/questions/26052815/…
Pieter

4
ตอนนี้คุณต้องเพิ่ม "!" ในบรรทัดที่สองสำหรับ NSURL NSURL (สตริง: "mailto: (email)")!
anthonyqz

4
ทำไมจึงบอกว่าสิ่งนี้ใช้ได้เฉพาะใน ios 10 หรือใหม่กว่าเมื่อคำตอบชัดเจนว่าอายุ 3 ปี
pete

1
ตัวอย่าง Swift 4 / iOS 10+: UIApplication.shared.open (url, options: [:], completeHandler: nil) การส่งพจนานุกรมที่ว่างเปล่าสำหรับตัวเลือกจะให้ผลลัพธ์เช่นเดียวกับการเรียก openURL
Luca Ventura

ขอบคุณ ... มันช่วยได้มาก :) :)
Anjali jariwala

62

แม้ว่าคำตอบอื่น ๆ จะถูกต้อง แต่คุณไม่มีทางรู้ได้ว่า iPhone / iPad ที่ใช้งานแอปพลิเคชันของคุณติดตั้งแอป Mail ของ Apple ไว้หรือไม่เนื่องจากผู้ใช้สามารถลบได้

จะดีกว่าในการรองรับไคลเอนต์อีเมลหลายตัว รหัสต่อไปนี้จะจัดการกับการส่งอีเมลด้วยวิธีที่สละสลวยยิ่งขึ้น ขั้นตอนของรหัสคือ:

  • หากติดตั้งแอพ Mail แล้วให้เปิดผู้แต่งของ Mail ที่กรอกข้อมูลไว้ล่วงหน้า
  • ไม่เช่นนั้นให้ลองเปิดแอป 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: .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ไฟล์ที่อนุญาตพิเศษของโครงร่างแบบสอบถาม URl ที่ใช้

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

4
ทำได้ดี. นี่เป็นคำตอบที่สมบูรณ์ที่สุดและสามารถขยายได้อย่างง่ายดายสำหรับแอปไคลเอ็นต์อีเมลอื่น ๆ IMHO ฉันไม่คิดว่าจะเป็นที่ยอมรับในปลายปี 2019 ที่จะบอกคน ๆ นั้นว่า "ขอโทษคุณโชคไม่ดี" หากพวกเขาไม่ได้ใช้แอป Apple Mail เริ่มต้นตามที่โซลูชันอื่น ๆ แนะนำ สิ่งนี้แก้ไขข้อบกพร่องนั้น
wildcat12

วิธีนี้ใช้ได้กับ HTML หรือไม่ ฉันไม่สามารถแสดงได้อย่างถูกต้อง
Matthew Bradshaw

@MatthewBradshaw คุณสามารถรองรับ HTML สำหรับตัวสร้างเมลเริ่มต้นโดยตั้งค่าisHTMLในโค้ดด้านบนเป็น true สำหรับไคลเอนต์อื่นดูเหมือนว่าจะเป็นไปไม่ได้สำหรับการอ่านเพิ่มเติมโปรดดูstackoverflow.com/questions/5620324/mailto-link-with-html-body
WebMajstr

1
ขอบคุณกระทะนี้เยี่ยมมาก ฉันแก้ไขเล็กน้อยเพื่อให้ผู้ใช้เลือกไคลเอนต์ที่ต้องการ (ฉันกำลังกรองพวกเขาล่วงหน้าด้วย canOpenUrl) Btw body สำหรับ Microsoft Outlook ทำงานได้ดี :-)
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
AustinT

3
เพิ่ม "import MessageUI" ในการนำเข้าของคุณและอย่าลืมเพิ่มตัวเลือก "MFMailComposeViewControllerDelegate" ในการประกาศคลาสของคุณเช่น: class myClass: UIViewController, MFMailComposeViewControllerDelegate {
Jalakoo

MFMailComposeViewController () คืนค่าศูนย์ให้ฉัน
ilan

2
นอกจากนี้ยังมีปัญหา: 'NSInvalidArgumentException', reason: 'Application tried to present a nil modal view controller on target. แอพขัดข้องในบางอุปกรณ์ (iPhone 5, iPhone 6 และ iPad Mini)
Spacemonkey

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

17

สำหรับ 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 ด้วยที่อยู่อีเมลที่คุณต้องการ


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

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


10

นี่คือการอัปเดตสำหรับ Swift 4 หากคุณต้องการเปิดโปรแกรมรับส่งเมลผ่านทางURL:

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

สิ่งนี้ใช้ได้ดีสำหรับฉัน :)


9

นี่เป็นการแก้ปัญหาแบบตรงไปตรงมาของ 3 ขั้นตอนใน Swift

import MessageUI

เพิ่มเพื่อให้สอดคล้องกับ Delegate

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 callback เพื่อปิดหน้าต่างเมล


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)
     }
  • ขยายดูควบคุมของคุณและสอดคล้องกับ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 เสมอ (โอ้และ canOpenURL สำหรับ "mailto" ก็เป็นจริงเช่นกัน) แม้ว่าจะมีอื่น ๆ แอพเมล นี่จึงไม่ได้ผลแน่นอน
NeverwinterMoon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.