Come aprire l'app di posta da Swift


119

Sto lavorando su una semplice app rapida in cui l'utente inserisce un indirizzo email e preme un pulsante che apre l'app di posta, con l'indirizzo inserito nella barra degli indirizzi. So come farlo in Objective-C, ma ho problemi a farlo funzionare in Swift.

Risposte:


240

Puoi utilizzare i link mailto: semplici in iOS per aprire l'app di posta.

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
Forse vale la pena aggiungere che questo non funziona nel simulatore, solo sul dispositivo ... Vedi stackoverflow.com/questions/26052815/…
Pieter

4
ora devi aggiungere "!" nella seconda riga, per NSURL NSURL (stringa: "mailto: (email)")!
anthonyqz

4
perché si dice che questo è disponibile solo su iOS 10 o più recente quando la risposta è chiaramente di 3 anni
pete

1
Swift 4 / iOS 10+ esempio: UIApplication.shared.open (url, options: [:], completamentoHandler: nil) Il passaggio di un dizionario vuoto per le opzioni produce lo stesso risultato della chiamata di openURL.
Luca Ventura

Grazie ... Aiuta molto :) :)
Anjali jariwala

62

Mentre le altre risposte sono tutte corrette, non puoi mai sapere se l'iPhone / iPad su cui è in esecuzione la tua applicazione ha l'app Mail di Apple installata o meno in quanto può essere eliminata dall'utente.

È meglio supportare più client di posta elettronica. Il codice seguente gestisce l'invio di e-mail in modo più grazioso. Il flusso del codice è:

  • Se l'app Mail è installata, apri il compositore di Mail precompilato con i dati forniti
  • Altrimenti, prova ad aprire l'app Gmail, quindi Outlook, quindi Yahoo mail, quindi Spark, in questo ordine
  • Se nessuno di questi client è installato, fallback al valore predefinito mailto:..che richiede all'utente di installare l'app Mail di Apple.

Il codice è scritto in 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)
        }
    }

Tieni presente che ho intenzionalmente perso il corpo dell'app Outlook, poiché non è in grado di analizzarlo.

È inoltre necessario aggiungere il codice seguente al Info.plistfile che inserisce nella whitelist gli schemi di query URl utilizzati.

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

4
Molto bene. Questa è la risposta più completa ed è facilmente estendibile per altre app client di posta elettronica. IMHO, non penso sia accettabile alla fine del 2019 dire alla persona "scusa, sei sfortunata" se non usa l'app predefinita di Apple Mail, come suggerisce la maggior parte delle altre soluzioni. Questo risolve quella carenza.
wildcat12

Questo metodo funziona con l'HTML? Non riesco a visualizzarlo correttamente.
Matthew Bradshaw

@ MatthewBradshaw puoi supportare l'HTML per il compositore di posta predefinito impostando isHTMLil codice sopra su true. Per altri clienti, non sembra essere possibile, per ulteriori approfondimenti vedi stackoverflow.com/questions/5620324/mailto-link-with-html-body
WebMajstr

1
Grazie, è fantastico. L'ho modificato leggermente per consentire all'utente di scegliere il client che preferisce (li sto filtrando in anticipo con canOpenUrl). Btw body per Microsoft Outlook funziona bene :-)
Filip

È brillante! Qualcuno ha fatto questo per SwiftUI?
Averett

55

Non sono sicuro se desideri passare all'app di posta o semplicemente aprire e inviare un'e-mail. Per quest'ultima opzione collegata a un pulsante 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
Sto riscontrando problemi in cui la funzione delegato mailComposeController non viene chiamata.
AustinT

3
Aggiungi "import MessageUI" alle tue importazioni e assicurati di aggiungere l'opzione "MFMailComposeViewControllerDelegate" alla dichiarazione della tua classe come: class myClass: UIViewController, MFMailComposeViewControllerDelegate {
Jalakoo

MFMailComposeViewController () restituisce zero per me
ilan

2
Pur avendo problemi: 'NSInvalidArgumentException', reason: 'Application tried to present a nil modal view controller on target. L'app si arresta in modo anomalo in alcuni dispositivi (iPhone 5, iPhone 6 e iPad Mini)
Spacemonkey

23

In Swift 3 ti assicuri di aggiungere import MessageUIe deve essere conforme al MFMailComposeViewControllerDelegateprotocollo.

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

Protocollo:

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

17

Per Swift 4.2+ e 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)
}

Sostituisci TEST@EXAMPLE.COM con il tuo indirizzo email desiderato.


16

Swift 2, con verifica della disponibilità :

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

Ecco come appare 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

Risposta aggiornata di Stephen Groom per Swift 3

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

10

Ecco un aggiornamento per Swift 4 se stai semplicemente cercando di aprire il client di posta tramite URL:

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

Questo ha funzionato perfettamente per me :)


9

Questa è una soluzione semplice di 3 passaggi in Swift.

import MessageUI

Aggiungi per conformare il Delegato

MFMailComposeViewControllerDelegate

E crea il tuo metodo:

    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

Dovresti provare a inviare con il compositore di posta integrato e, se fallisce, prova con la condivisione:

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

errore: "Questa app non è autorizzata a eseguire query per lo schema 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)
}

Nota che non tutti gli utenti hanno il loro dispositivo configurato per inviare e-mail, motivo per cui dobbiamo controllare il risultato di canSendMail () prima di provare a inviare. Nota anche che devi catturare il callback didFinishWith per chiudere la finestra della posta.


1

Nel controller della vista da dove vuoi che la tua app di posta si apra al tocco.

  • Nella parte superiore del file, importa MessageUI .
  • Metti questa funzione nel tuo Controller.

    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)
     }
  • Estendi il controller di visualizzazione e conformati a MFMailComposeViewControllerDelegate .

  • Metti questo metodo e gestisci il fallimento, inviando le tue mail.

    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

Per quelli di noi ancora in ritardo su Swift 2.3, ecco la risposta di Gordon nella nostra sintassi:

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

0

Per Swift 4.2 e versioni successive

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

Consenti all'utente di scegliere molte opzioni di posta (come iCloud, google, yahoo, Outlook.com - se nessuna posta è preconfigurata nel suo telefono) per inviare e-mail.


1
Nel mio caso, con iOS 13, quando si chiama UIApplication.shared.open, il sistema operativo mostrava sempre una finestra di dialogo che proponeva di installare Mail.app (oh, e canOpenURL per "mailto" è sempre vero anche), anche se ce ne sono altri app di posta. Quindi questo sicuramente non sta funzionando.
NeverwinterMoon
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.