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.

Réponses:


240

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

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

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>

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 = ["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
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(["ved.ios@yopmail.com"])
    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)
}

17

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

Remplacez TEST@EXAMPLE.COM par l'adresse e-mail souhaitée.


16

Swift 2, avec contrôle de 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

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

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

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

10

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

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

Cela a parfaitement fonctionné pour moi :)


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(["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

Vous devriez essayer d'envoyer avec le composeur de courrier intégré, et si cela échoue, essayez avec 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)
            }
        }
    }
}

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 = ["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)
}

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.


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(["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)
     }
  • É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)
    }

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 = "foo@bar.com"
if let url = NSURL(string: "mailto:\(email)") {
   UIApplication.sharedApplication().openURL(url)
}

0

Pour Swift 4.2 et supérieur

let supportEmail = "abc@xyz.com"
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.


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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.