Cómo abrir la aplicación de correo de Swift

119

Estoy trabajando en una aplicación simple y rápida en la que el usuario ingresa una dirección de correo electrónico y presiona un botón que abre la aplicación de correo, con la dirección ingresada en la barra de direcciones. Sé cómo hacer esto en Objective-C, pero tengo problemas para que funcione en Swift.

Jesse.H
fuente

Respuestas:

240

Puede utilizar simples enlaces mailto: en iOS para abrir la aplicación de correo.

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)
  }    
}
Esteban novio
fuente
77
Quizás valga la pena agregar que esto no funciona en el simulador, solo en el dispositivo ... Ver stackoverflow.com/questions/26052815/…
Pieter
4
ahora debe agregar "!" en la segunda línea, para NSURL NSURL (string: "mailto: (email)")!
anthonyqz
4
¿Por qué dice esto sólo está disponible en IOS 10 o más reciente, cuando la respuesta es claramente 3 años de edad
Pete
1
Ejemplo de Swift 4 / iOS 10+: UIApplication.shared.open (url, options: [:], executionHandler: nil) Pasar un diccionario vacío para opciones produce el mismo resultado que llamar a openURL.
Luca Ventura
Gracias ... Ayuda mucho :) :)
Anjali jariwala
61

Si bien otras respuestas son correctas, nunca se puede saber si el iPhone / iPad que está ejecutando su aplicación tiene la aplicación de correo de Apple instalada o no, ya que el usuario puede eliminarla.

Es mejor admitir varios clientes de correo electrónico. El siguiente código maneja el envío de correo electrónico de una manera más elegante. El flujo del código es:

  • Si la aplicación Mail está instalada, abra el redactor de Mail previamente completado con los datos proporcionados
  • De lo contrario, intente abrir la aplicación Gmail, luego Outlook, luego Yahoo Mail, luego Spark, en este orden
  • Si ninguno de esos clientes está instalado, vuelva al valor predeterminado mailto:..que solicita al usuario que instale la aplicación Mail de Apple.

El código está escrito 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)
        }
    }

Tenga en cuenta que intencionalmente me perdí el cuerpo de la aplicación Outlook, ya que no es capaz de analizarlo.

También debe agregar el siguiente código al Info.plistarchivo que incluye en la lista blanca los esquemas de consulta URl que se utilizan.

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>googlegmail</string>
    <string>ms-outlook</string>
    <string>readdle-spark</string>
    <string>ymail</string>
</array>
WebMajstr
fuente
4
Bien hecho. Esta es la respuesta más completa y se puede ampliar fácilmente para otras aplicaciones de cliente de correo electrónico. En mi humilde opinión, no creo que sea aceptable a finales de 2019 decirle a la persona "lo siento, no tienes suerte" si no usa la aplicación Apple Mail predeterminada, como sugieren la mayoría de las otras soluciones. Esto corrige esa deficiencia.
wildcat12
¿Este método funciona con HTML? No puedo hacer que se muestre correctamente.
Matthew Bradshaw
@MatthewBradshaw puede admitir HTML para el redactor de correo predeterminado configurando isHTMLel código anterior en verdadero. Para otros clientes, no parece ser posible; para obtener más información, consulte stackoverflow.com/questions/5620324/mailto-link-with-html-body
WebMajstr
1
Gracias, esto funciona genial. Lo modifiqué ligeramente para permitir que el usuario elija el cliente de su preferencia (los estoy filtrando por adelantado con canOpenUrl). Por cierto, el cuerpo para Microsoft Outlook funciona bien :-)
Filip
¡Esto es brillante! ¿Alguien ha hecho esto por SwiftUI?
Averett
55

No estoy seguro de si desea cambiar a la aplicación de correo o simplemente abrir y enviar un correo electrónico. Para la última opción vinculada a un botón 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
fuente
1
Tengo problemas en los que no se llama a la función delegada mailComposeController.
AustinT
3
Agregue "import MessageUI" a sus importaciones y asegúrese de agregar la opción "MFMailComposeViewControllerDelegate" a su declaración de clase como: class myClass: UIViewController, MFMailComposeViewControllerDelegate {
Jalakoo
MFMailComposeViewController () devuelve cero para mí
ilan
2
También tener problemas: 'NSInvalidArgumentException', reason: 'Application tried to present a nil modal view controller on target. La aplicación se bloquea en algunos dispositivos (iPhone 5, iPhone 6 y iPad Mini)
Spacemonkey
23

En Swift 3, asegúrese de agregar import MessageUIy las necesidades se ajustan al MFMailComposeViewControllerDelegateprotocolo.

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

Protocolo:

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

Para Swift 4.2+ y 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)
}

Reemplace [email protected] con su dirección de correo electrónico deseada.

Méhdico
fuente
16

Swift 2, con verificación de disponibilidad :

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
fuente
15

Así es como se ve 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
fuente
12

Respuesta actualizada de Stephen Groom para Swift 3

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

Aquí hay una actualización para Swift 4 si simplemente está buscando abrir el cliente de correo a través de URL:

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

Esto funcionó perfectamente bien para mí :)

Nii Mantse
fuente
9

Esta es una solución sencilla de 3 pasos en Swift.

import MessageUI

Agregar para conformar el Delegado

MFMailComposeViewControllerDelegate

Y solo crea tu método:

    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)
}
María Ortega
fuente
4

Debería intentar enviar con el redactor de correo incorporado, y si eso falla, intente con compartir:

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
fuente
error: "Esta aplicación no puede consultar el esquema 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)
}

Tenga en cuenta que no todos los usuarios tienen su dispositivo configurado para enviar correos electrónicos, por lo que debemos verificar el resultado de canSendMail () antes de intentar enviar. Tenga en cuenta también que debe capturar la devolución de llamada didFinishWith para cerrar la ventana de correo.

Nishal Solanki
fuente
1

En el controlador de vista desde donde desea que se abra su aplicación de correo con el toque.

  • En la parte superior del archivo, importe MessageUI .
  • Pon esta función dentro de tu controlador.

    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)
     }
  • Extienda su View Controller y cumpla con MFMailComposeViewControllerDelegate .

  • Pon este método y maneja el fallo, enviando tus 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
fuente
0

Para aquellos de nosotros que todavía nos quedamos atrás en Swift 2.3, aquí está la respuesta de Gordon en nuestra sintaxis:

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

Para Swift 4.2 y superior

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

Permita que el usuario elija muchas opciones de correo (como iCloud, google, yahoo, Outlook.com, si no hay ningún correo preconfigurado en su teléfono) para enviar correo electrónico.

iHarshil
fuente
1
En mi caso, con iOS 13, al llamar a UIApplication.shared.open, el sistema operativo siempre mostraba un cuadro de diálogo que ofrecía instalar Mail.app (oh, y canOpenURL para "mailto" también es siempre cierto), incluso si hay otros aplicaciones de correo. Así que esto definitivamente no está funcionando.
NeverwinterMoon