Cara membuka aplikasi email dari Swift

119

Saya sedang mengerjakan aplikasi cepat sederhana di mana pengguna memasukkan alamat email dan menekan tombol yang membuka aplikasi email, dengan alamat yang dimasukkan di bilah alamat. Saya tahu cara melakukan ini di Objective-C, tapi saya kesulitan membuatnya berfungsi di Swift.

Jesse.H
sumber

Jawaban:

240

Anda dapat menggunakan tautan mailto: sederhana di iOS untuk membuka aplikasi email.

let email = "[email protected]"
if let url = URL(string: "mailto:\(email)") {
  if #available(iOS 10.0, *) {
    UIApplication.shared.open(url)
  } else {
    UIApplication.shared.openURL(url)
  }    
}
Stephen Groom
sumber
77
Mungkin patut ditambahkan bahwa ini tidak berfungsi di simulator, hanya di perangkat ... Lihat stackoverflow.com/questions/26052815/…
Pieter
4
sekarang Anda perlu menambahkan "!" di baris kedua, untuk NSURL NSURL (string: "mailto: (email)")!
anthonyqz
4
mengapa dikatakan bahwa ini hanya tersedia di iOS 10 atau yang lebih baru ketika jawabannya jelas berusia 3 tahun
pete
1
Contoh Swift 4 / iOS 10+: UIApplication.shared.open (url, options: [:], completeHandler: nil) Meneruskan kamus kosong untuk pilihan menghasilkan hasil yang sama seperti memanggil openURL.
Luca Ventura
Terima kasih ... Ini sangat membantu :) :)
Anjali jariwala
62

Sementara jawaban lain semuanya benar, Anda tidak akan pernah tahu apakah iPhone / iPad yang menjalankan aplikasi Anda telah menginstal aplikasi Mail Apple atau tidak karena dapat dihapus oleh pengguna.

Lebih baik mendukung banyak klien email. Kode berikut menangani pengiriman email dengan cara yang lebih anggun. Alur kodenya adalah:

  • Jika aplikasi Mail diinstal, buka pembuat Mail yang telah diisi sebelumnya dengan data yang disediakan
  • Jika tidak, coba buka aplikasi Gmail, lalu Outlook, lalu Yahoo mail, lalu Spark, dalam urutan ini
  • Jika tidak ada dari klien tersebut yang diinstal, kembali ke default mailto:..yang meminta pengguna untuk menginstal aplikasi Mail Apple.

Kode ditulis di Swift 5 :

    import MessageUI
    import UIKit

    class SendEmailViewController: UIViewController, MFMailComposeViewControllerDelegate {

        @IBAction func sendEmail(_ sender: UIButton) {
            // Modify following variables with your text / recipient
            let recipientEmail = "[email protected]"
            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)
        }
    }

Harap dicatat bahwa saya sengaja melewatkan isi untuk aplikasi Outlook, karena tidak dapat menguraikannya.

Anda juga harus menambahkan kode berikut ke Info.plistfile yang memasukkan skema kueri URl yang digunakan ke daftar putih.

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>googlegmail</string>
    <string>ms-outlook</string>
    <string>readdle-spark</string>
    <string>ymail</string>
</array>
WebMajstr
sumber
4
Sudah selesai dilakukan dengan baik. Ini adalah jawaban terlengkap dan mudah dikembangkan untuk aplikasi klien email lainnya. IMHO, menurut saya, di akhir tahun 2019 tidak boleh hanya memberi tahu orang tersebut "maaf, Anda kurang beruntung" jika mereka tidak menggunakan aplikasi default Apple Mail, seperti yang disarankan oleh sebagian besar solusi lain. Ini memperbaiki kekurangan itu.
kucing liar12
Apakah metode ini berfungsi dengan HTML? Saya tidak bisa menampilkannya dengan benar.
Matthew Bradshaw
@MatthewBradshaw Anda dapat mendukung HTML untuk pembuat email default dengan menyetel isHTMLkode di atas ke true. Untuk klien lain, tampaknya tidak mungkin, untuk bacaan lebih lanjut lihat stackoverflow.com/questions/5620324/mailto-link-with-html-body
WebMajstr
1
Terima kasih, wajan ini bagus. Saya memodifikasinya sedikit agar pengguna memilih klien preferensi mereka (saya memfilternya terlebih dahulu dengan canOpenUrl). Btw body untuk Microsoft Outlook berfungsi dengan baik :-)
Filip
Ini luar biasa! Apakah ada yang melakukan ini untuk SwiftUI?
Averett
55

Saya tidak yakin apakah Anda ingin beralih ke aplikasi email itu sendiri atau hanya membuka dan mengirim email. Untuk opsi terakhir yang ditautkan ke tombol 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 = ["[email protected]"]
    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)
    }

    }
Steve Rosenberg
sumber
1
Saya mengalami masalah di mana fungsi delegasi mailComposeController tidak dipanggil.
AustinT
3
Tambahkan "impor MessageUI" ke impor Anda dan pastikan untuk menambahkan opsi "MFMailComposeViewControllerDelegate" ke deklarasi kelas Anda seperti: class myClass: UIViewController, MFMailComposeViewControllerDelegate {
Jalakoo
MFMailComposeViewController () mengembalikan nol untuk saya
ilan
2
Juga mengalami masalah: 'NSInvalidArgumentException', reason: 'Application tried to present a nil modal view controller on target. Aplikasi mogok di beberapa perangkat (iPhone 5, iPhone 6 dan iPad Mini)
Spacemonkey
23

Di Swift 3 Anda memastikan untuk menambah import MessageUIdan kebutuhan sesuai dengan MFMailComposeViewControllerDelegateprotokol.

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

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

Protokol:

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

Untuk Swift 4.2+ dan iOS 9+

let appURL = URL(string: "mailto:[email protected]")!

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

Ganti [email protected] dengan alamat email yang Anda inginkan.

Mehdico
sumber
16

Swift 2, dengan pemeriksaan ketersediaan :

import MessageUI

if MFMailComposeViewController.canSendMail() {
    let mail = MFMailComposeViewController()
    mail.mailComposeDelegate = self
    mail.setToRecipients(["[email protected]"])
    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)
}
Ixx
sumber
15

Berikut tampilannya untuk Swift 4:

import MessageUI

if MFMailComposeViewController.canSendMail() {
    let mail = MFMailComposeViewController()
    mail.mailComposeDelegate = self
    mail.setToRecipients(["[email protected]"])
    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)
    }
Yuval
sumber
12

Jawaban terbaru dari Stephen Groom untuk Swift 3

let email = "[email protected]"
let url = URL(string: "mailto:\(email)")
UIApplication.shared.openURL(url!)
Ben W.
sumber
10

Berikut ini pembaruan untuk Swift 4 jika Anda hanya ingin membuka klien email melalui URL:

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

Ini bekerja dengan baik untuk saya :)

Nii Mantse
sumber
9

Ini adalah solusi langsung dari 3 langkah di Swift.

import MessageUI

Tambahkan untuk menyesuaikan Delegasi

MFMailComposeViewControllerDelegate

Dan buat saja metode Anda:

    func sendEmail() {
    if MFMailComposeViewController.canSendMail() {
        let mail = MFMailComposeViewController()
        mail.mailComposeDelegate = self
        mail.setToRecipients(["[email protected]"])
        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)
}
Maria Ortega
sumber
4

Anda harus mencoba mengirim dengan pembuat email built-in, dan jika gagal, coba dengan share:

func contactUs() {

    let email = "[email protected]" // 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)
            }
        }
    }
}
lenooh
sumber
error: "Aplikasi ini tidak diizinkan untuk meminta skema 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 = ["[email protected]"]
   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)
}

Perhatikan bahwa tidak semua pengguna mengonfigurasi perangkatnya untuk mengirim email, itulah sebabnya kami perlu memeriksa hasil canSendMail () sebelum mencoba mengirim. Perhatikan juga bahwa Anda perlu menangkap callback didFinishWith untuk menutup jendela email.

Nishal Solanki
sumber
1

Di pengontrol tampilan dari mana Anda ingin aplikasi email Anda terbuka di keran.

  • Di bagian atas file lakukan, impor MessageUI .
  • Letakkan fungsi ini di dalam Controller Anda.

    func showMailComposer(){
    
      guard MFMailComposeViewController.canSendMail() else {
           return
      }
      let composer = MFMailComposeViewController()
      composer.mailComposeDelegate = self
      composer.setToRecipients(["[email protected]"]) // email id of the recipient
      composer.setSubject("testing!!!")
      composer.setMessageBody("this is a test mail.", isHTML: false)
      present(composer, animated: true, completion: nil)
     }
  • Perluas Pengontrol Tampilan Anda dan sesuaikan dengan MFMailComposeViewControllerDelegate .

  • Gunakan metode ini dan tangani kegagalan pengiriman email Anda.

    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)
    }
Shiv Prakash
sumber
0

Bagi kita yang masih tertinggal di Swift 2.3 berikut adalah jawaban Gordon dalam sintaks kita:

let email = "[email protected]"
if let url = NSURL(string: "mailto:\(email)") {
   UIApplication.sharedApplication().openURL(url)
}
Paul Lehn
sumber
0

Untuk Swift 4.2 dan yang lebih baru

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

Beri pengguna untuk memilih banyak opsi email (seperti iCloud, google, yahoo, Outlook.com - jika tidak ada email yang dikonfigurasi sebelumnya di teleponnya) untuk mengirim email.

iHarshil
sumber
1
Dalam kasus saya, dengan iOS 13, saat memanggil UIApplication.shared.open, OS akan selalu menampilkan dialog yang menawarkan untuk menginstal Mail.app (oh, dan canOpenURL untuk "mailto" juga selalu benar), bahkan jika ada yang lain aplikasi email. Jadi ini pasti tidak berhasil.
NeverwinterMoon