Comment ouvrir l'application de messagerie depuis Swift

119

Je travaille sur une simple application rapide où l'utilisateur entre une adresse e-mail et appuie sur un bouton qui ouvre l'application de messagerie, avec l'adresse saisie dans la barre d'adresse. Je sais comment faire cela en Objective-C, mais j'ai du mal à le faire fonctionner dans Swift.

Jesse.H
la source

Réponses:

240

Vous pouvez utiliser de simples liens mailto: dans iOS pour ouvrir l'application de messagerie.

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
la source
77
Peut-être vaut-il la peine d'ajouter que cela ne fonctionne pas dans le simulateur, uniquement sur l'appareil ... Voir stackoverflow.com/questions/26052815
Pieter
4
maintenant, vous devez ajouter "!" dans la deuxième ligne, pour la NSURL NSURL (string: "mailto: (email)")!
anthonyqz
4
pourquoi dit-il que cela n'est disponible que sur iOS 10 ou plus récent lorsque la réponse est clairement âgée de 3 ans
pete
1
Exemple Swift 4 / iOS 10+: UIApplication.shared.open (url, options: [:], completionHandler: nil) Passer un dictionnaire vide pour les options produit le même résultat que l'appel openURL.
Luca Ventura
Merci ... ça aide beaucoup :) :)
Anjali jariwala
62

Bien que les autres réponses soient toutes correctes, vous ne pouvez jamais savoir si l'application Mail d'Apple est installée sur l'iPhone / iPad qui exécute votre application, car elle peut être supprimée par l'utilisateur.

Il est préférable de prendre en charge plusieurs clients de messagerie. Le code suivant gère l'envoi des e-mails d'une manière plus gracieuse. Le flux du code est:

  • Si l'application Mail est installée, ouvrez l'éditeur de Mail pré-rempli avec les données fournies
  • Sinon, essayez d'ouvrir l'application Gmail, puis Outlook, puis Yahoo mail, puis Spark, dans cet ordre
  • Si aucun de ces clients n'est installé, retournez à la valeur par défaut mailto:..qui invite l'utilisateur à installer l'application Mail d'Apple.

Le code est écrit en 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)
        }
    }

Veuillez noter que j'ai volontairement oublié le corps de l'application Outlook, car elle ne peut pas l'analyser.

Vous devez également ajouter le code suivant au Info.plistfichier qui répertorie les schémas de requête URl utilisés.

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>googlegmail</string>
    <string>ms-outlook</string>
    <string>readdle-spark</string>
    <string>ymail</string>
</array>
WebMajstr
la source
4
Bien joué. C'est la réponse la plus complète et est facilement extensible pour d'autres applications clientes de messagerie. À mon humble avis, je ne pense pas qu'il soit acceptable à la fin de 2019 de simplement dire à la personne "désolé, vous n'avez pas de chance" si elle n'utilise pas l'application Apple Mail par défaut, comme le suggèrent la plupart des autres solutions. Cela corrige cette lacune.
wildcat12
Cette méthode fonctionne-t-elle avec HTML? Je ne peux pas l'afficher correctement.
Matthew Bradshaw le
@MatthewBradshaw, vous pouvez prendre en charge HTML pour l'éditeur de courrier par défaut en définissant isHTMLdans le code ci-dessus sur true. Pour les autres clients, cela ne semble pas possible, pour plus d'informations, voir stackoverflow.com/questions/5620324/mailto-link-with-html-body
WebMajstr
1
Merci, ça marche super. Je l'ai légèrement modifié pour permettre à l'utilisateur de choisir le client de sa préférence (je le filtre à l'avance avec canOpenUrl). Le corps Btw pour Microsoft Outlook fonctionne bien :-)
Filip le
C'est génial! Quelqu'un a-t-il fait cela pour SwiftUI?
Averett
55

Je ne sais pas si vous souhaitez basculer vers l'application de messagerie elle-même ou simplement ouvrir et envoyer un e-mail. Pour cette dernière option liée à un bouton 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
la source
1
Je rencontre des problèmes où la fonction de délégué mailComposeController n'est pas appelée.
AustinT
3
Ajoutez "import MessageUI" à vos importations et assurez-vous d'ajouter l'option "MFMailComposeViewControllerDelegate" à votre déclaration de classe comme: class myClass: UIViewController, MFMailComposeViewControllerDelegate {
Jalakoo
MFMailComposeViewController () renvoie nul pour moi
ilan
2
Ayant également des questions: 'NSInvalidArgumentException', reason: 'Application tried to present a nil modal view controller on target. L'application plante sur certains appareils (iPhone 5, iPhone 6 et iPad Mini)
Spacemonkey
23

Dans Swift 3, vous vous assurez d'ajouter import MessageUIet de respecter le MFMailComposeViewControllerDelegateprotocole.

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

Protocole:

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

Pour Swift 4.2+ et 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)
}

Remplacez [email protected] par l'adresse e-mail souhaitée.

Mehdico
la source
16

Swift 2, avec contrôle de disponibilité :

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
la source
15

Voici à quoi il ressemble pour 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
la source
12

Réponse mise à jour de Stephen Groom pour Swift 3

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

Voici une mise à jour pour Swift 4 si vous cherchez simplement à ouvrir le client de messagerie via un URL:

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

Cela a parfaitement fonctionné pour moi :)

Nii Mantse
la source
9

Il s'agit d'une solution simple en 3 étapes dans Swift.

import MessageUI

Ajouter pour conformer le délégué

MFMailComposeViewControllerDelegate

Et créez simplement votre méthode:

    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
la source
4

Vous devriez essayer d'envoyer avec le composeur de courrier intégré, et si cela échoue, essayez avec 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
la source
erreur: "Cette application n'est pas autorisée à interroger le schéma 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)
}

Notez que tous les utilisateurs n'ont pas configuré leur appareil pour envoyer des e-mails, c'est pourquoi nous devons vérifier le résultat de canSendMail () avant d'essayer d'envoyer. Notez également que vous devez intercepter le rappel didFinishWith pour fermer la fenêtre de messagerie.

Nishal Solanki
la source
1

Dans le contrôleur d'affichage à partir duquel vous souhaitez que votre application de messagerie s'ouvre au toucher.

  • En haut du fichier, importez MessageUI .
  • Mettez cette fonction dans votre contrôleur.

    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)
     }
  • Étendez votre View Controller et conformez-vous à MFMailComposeViewControllerDelegate .

  • Mettez cette méthode et gérez l'échec, l'envoi de vos mails.

    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
la source
0

Pour ceux d'entre nous qui sont encore à la traîne sur Swift 2.3, voici la réponse de Gordon dans notre syntaxe:

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

Pour Swift 4.2 et supérieur

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

Donnez à l'utilisateur le choix de nombreuses options de messagerie (comme iCloud, google, yahoo, Outlook.com - si aucun e-mail n'est préconfiguré dans son téléphone) pour envoyer un e-mail.

iHarshil
la source
1
Dans mon cas, avec iOS 13, lors de l'appel de UIApplication.shared.open, le système d'exploitation afficherait toujours une boîte de dialogue proposant d'installer Mail.app (oh, et canOpenURL pour "mailto" est toujours vrai aussi), même s'il y en a d'autres applications de messagerie. Donc, cela ne fonctionne certainement pas.
NeverwinterMoon