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.

Respuestas:


240

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

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

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>

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

17

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

Reemplace TEST@EXAMPLE.COM con su dirección de correo electrónico deseada.


16

Swift 2, con verificación de disponibilidad :

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

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

Respuesta actualizada de Stephen Groom para Swift 3

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

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 = "foo@bar.com"
if let url = URL(string: "mailto:\(email)") {
   UIApplication.shared.open(url, options: [:], completionHandler: nil)
}

Esto funcionó perfectamente bien para mí :)


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

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

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

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

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.


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

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

0

Para Swift 4.2 y superior

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


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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.