Jak otworzyć aplikację pocztową z Swift


119

Pracuję nad prostą szybką aplikacją, w której użytkownik wprowadza adres e-mail i naciska przycisk, który otwiera aplikację pocztową, z wpisanym adresem w pasku adresu. Wiem, jak to zrobić w Objective-C, ale mam problem z uruchomieniem go w Swift.

Odpowiedzi:


241

Możesz użyć prostych linków mailto: w iOS, aby otworzyć aplikację pocztową.

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
Może warto dodać, że to nie działa w symulatorze, tylko na urządzeniu ... Zobacz stackoverflow.com/questions/26052815/…
Pieter

4
teraz musisz dodać „!” w drugim wierszu dla NSURL NSURL (string: "mailto: (email)")!
anthonyqz

4
dlaczego jest napisane, że jest to dostępne tylko na iOS 10 lub nowszym, gdy odpowiedź jest wyraźnie sprzed 3 lat
pete

1
Przykład języka Swift 4 / iOS 10+: UIApplication.shared.open (url, options: [:], completeHandler: nil) Przekazanie pustego słownika opcji daje taki sam wynik, jak wywołanie openURL.
Luca Ventura

Dzięki ... To bardzo pomaga :) :)
Anjali jariwala

62

Podczas gdy inne odpowiedzi są poprawne, nigdy nie możesz wiedzieć, czy iPhone / iPad, na którym działa Twoja aplikacja, ma zainstalowaną aplikację Apple Mail, czy nie, ponieważ może ją usunąć użytkownik.

Lepiej jest obsługiwać wielu klientów poczty e-mail. Poniższy kod obsługuje wysyłanie wiadomości e-mail w bardziej elegancki sposób. Przepływ kodu to:

  • Jeśli zainstalowano aplikację Mail, otwórz edytor Mail, który jest wstępnie wypełniony podanymi danymi
  • W przeciwnym razie spróbuj otworzyć aplikację Gmail, następnie Outlook, następnie Yahoo Mail i Spark, w tej kolejności
  • Jeśli żaden z tych klientów nie jest zainstalowany, powróć do wartości domyślnej, mailto:..która monituje użytkownika o zainstalowanie aplikacji Apple Mail.

Kod jest napisany w języku 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)
        }
    }

Pamiętaj, że celowo przegapiłem treść aplikacji Outlook, ponieważ nie jest ona w stanie jej przeanalizować.

Musisz również dodać następujący kod do Info.plistpliku, który umieszcza na białej liście schematy zapytań URl, które są używane.

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

4
Dobra robota. To jest najbardziej kompletna odpowiedź i można ją łatwo rozszerzyć na inne aplikacje klientów poczty e-mail. IMHO, nie sądzę, aby pod koniec 2019 roku po prostu powiedzieć osobie „przepraszam, nie masz szczęścia”, jeśli nie używa domyślnej aplikacji Apple Mail, jak sugeruje większość innych rozwiązań. To naprawia ten brak.
wildcat12

Czy ta metoda działa z HTML? Nie mogę wyświetlić go poprawnie.
Matthew Bradshaw

@MatthewBradshaw możesz obsługiwać HTML dla domyślnego kompozytora poczty, ustawiając isHTMLw powyższym kodzie na true. W przypadku innych klientów wydaje się, że nie jest to możliwe, więcej informacji można znaleźć na stronie stackoverflow.com/questions/5620324/mailto-link-with-html-body
WebMajstr

1
Dzięki, to działa świetnie. Zmodyfikowałem go nieznacznie, aby umożliwić użytkownikowi wybranie klienta według jego preferencji (filtruję je z wyprzedzeniem za pomocą canOpenUrl). Btw body dla Microsoft Outlooka działa dobrze :-)
Filip

To jest genialne! Czy ktoś zrobił to dla SwiftUI?
Averett

55

Nie jestem pewien, czy chcesz przełączyć się na samą aplikację pocztową, czy po prostu otworzyć i wysłać wiadomość e-mail. W przypadku drugiej opcji połączonej z przyciskiem 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
Mam problemy, gdy funkcja delegata mailComposeController nie jest wywoływana.
AustinT,

3
Dodaj „import MessageUI” do swoich importów i pamiętaj o dodaniu opcji „MFMailComposeViewControllerDelegate” do deklaracji klasy, np .: class myClass: UIViewController, MFMailComposeViewControllerDelegate {
Jalakoo,

MFMailComposeViewController () return nil for me
ilan

2
Mając również kwestie: 'NSInvalidArgumentException', reason: 'Application tried to present a nil modal view controller on target. Awarie aplikacji na niektórych urządzeniach (iPhone 5, iPhone 6 i iPad Mini)
Spacemonkey

23

W Swift 3 upewnij się, że dodajesz import MessageUIi musisz być zgodny z MFMailComposeViewControllerDelegateprotokołem.

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

Protokół:

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

17

Dla Swift 4.2+ i 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)
}

Zastąp TEST@EXAMPLE.COM żądanym adresem e-mail.


16

Swift 2, ze sprawdzeniem dostępności :

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

Oto jak to wygląda dla 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

Zaktualizowana odpowiedź od Stephena Grooma dla Swift 3

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

10

Oto aktualizacja dla Swift 4, jeśli po prostu chcesz otworzyć klienta poczty za pomocą URL:

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

To działało idealnie dla mnie :)


9

To proste rozwiązanie 3 kroków w Swift.

import MessageUI

Dodaj, aby dostosować delegata

MFMailComposeViewControllerDelegate

I po prostu stwórz swoją metodę:

    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

Powinieneś spróbować wysłać za pomocą wbudowanego edytora poczty, a jeśli to się nie powiedzie, spróbuj z share:

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

błąd: „Ta aplikacja nie może
wysyłać

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

Zwróć uwagę, że nie wszyscy użytkownicy mają skonfigurowane urządzenie do wysyłania e-maili, dlatego przed próbą wysłania musimy sprawdzić wynik canSendMail (). Zauważ również, że musisz złapać wywołanie zwrotne didFinishWith, aby zamknąć okno poczty.


1

W kontrolerze widoku, z którego chcesz, aby aplikacja pocztowa otwierała się po dotknięciu.

  • W górnej części pliku zaimportuj MessageUI .
  • Umieść tę funkcję w swoim kontrolerze.

    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)
     }
  • Rozszerz swój kontroler widoku i dostosuj się do MFMailComposeViewControllerDelegate .

  • Skorzystaj z tej metody i poradzić sobie z niepowodzeniem, wysyłaniem wiadomości.

    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

Dla tych z nas, którzy wciąż pozostają w tyle w Swift 2.3, oto odpowiedź Gordona w naszej składni:

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

0

Dla Swift 4.2 i nowszych

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

Daj użytkownikowi możliwość wyboru wielu opcji poczty (takich jak iCloud, google, yahoo, Outlook.com - jeśli żadna poczta nie jest wstępnie skonfigurowana w jego telefonie) do wysyłania wiadomości e-mail.


1
W moim przypadku w iOS 13 podczas wywoływania UIApplication.shared.open system operacyjny zawsze pokazywał okno dialogowe z ofertą instalacji Mail.app (och, i canOpenURL dla „mailto” też jest zawsze prawdziwe), nawet jeśli są inne aplikacje pocztowe. Więc to zdecydowanie nie działa.
NeverwinterMoon
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.