Como abrir o aplicativo de e-mail do Swift

119

Estou trabalhando em um aplicativo rápido e simples, onde o usuário insere um endereço de e-mail e pressiona um botão que abre o aplicativo de e-mail, com o endereço inserido na barra de endereços. Eu sei como fazer isso em Objective-C, mas estou tendo problemas para fazer funcionar em Swift.

Jesse.H
fonte

Respostas:

240

Você pode usar links mailto: simples no iOS para abrir o aplicativo de e-mail.

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
fonte
77
Talvez valha a pena acrescentar que isso não funciona no simulador, apenas no dispositivo ... Consulte stackoverflow.com/questions/26052815/…
Pieter
4
agora você precisa adicionar "!" na segunda linha, para o NSURL NSURL (string: "mailto: (email)")!
anthonyqz
4
por que diz que só está disponível no iOS 10 ou mais recente quando a resposta é claramente 3 anos
pete
1
Exemplo do Swift 4 / iOS 10+: UIApplication.shared.open (url, options: [:], completedHandler: nil) Passar um dicionário vazio para opções produz o mesmo resultado que chamar openURL.
Luca Ventura
Obrigado ... Ajuda muito :) :)
Anjali jariwala
61

Embora as outras respostas estejam todas corretas, você nunca saberá se o iPhone / iPad que está executando seu aplicativo tem o aplicativo Mail da Apple instalado ou não, pois ele pode ser excluído pelo usuário.

É melhor oferecer suporte a vários clientes de e-mail. O código a seguir trata o envio de e-mail de uma forma mais elegante. O fluxo do código é:

  • Se o aplicativo Mail estiver instalado, abra o compositor do Mail pré-preenchido com os dados fornecidos
  • Caso contrário, tente abrir o aplicativo Gmail, Outlook, Yahoo mail e Spark, nesta ordem
  • Se nenhum desses clientes estiver instalado, volte ao padrão mailto:..que solicita que o usuário instale o aplicativo Mail da Apple.

O código é escrito em 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)
        }
    }

Observe que omiti intencionalmente o corpo do aplicativo Outlook, pois não é possível analisá-lo.

Você também deve adicionar o código a seguir ao Info.plistarquivo que lista os esquemas de consulta URl que são usados.

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>googlegmail</string>
    <string>ms-outlook</string>
    <string>readdle-spark</string>
    <string>ymail</string>
</array>
WebMajstr
fonte
4
Bem feito. Esta é a resposta mais completa e facilmente extensível para outros aplicativos de cliente de e-mail. IMHO, não acho que seja aceitável no final de 2019 apenas dizer à pessoa "desculpe, você está sem sorte" se ela não usar o aplicativo Apple Mail padrão, como a maioria das outras soluções sugere. Isso corrige essa deficiência.
wildcat12
Este método funciona com HTML? Não consigo exibi-lo corretamente.
Matthew Bradshaw
@MatthewBradshaw você pode oferecer suporte a HTML para o compositor de correio padrão definindo isHTMLo código acima como verdadeiro. Para outros clientes, não parece ser possível. Para mais informações, consulte stackoverflow.com/questions/5620324/mailto-link-with-html-body
WebMajstr
1
Obrigado, isso é ótimo. Eu modifiquei um pouco para permitir que o usuário escolha o cliente de sua preferência (estou filtrando-os antecipadamente com canOpenUrl). Btw body para Microsoft Outlook está funcionando bem :-)
Filip
Isto é brilhante! Alguém fez isso para SwiftUI?
Averett
55

Não tenho certeza se você deseja alternar para o próprio aplicativo de e-mail ou apenas abrir e enviar um e-mail. Para a última opção vinculada a um botão 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
fonte
1
Estou tendo problemas em que a função de delegado mailComposeController não está sendo chamada.
AustinT
3
Adicione "import MessageUI" às suas importações e certifique-se de adicionar a opção "MFMailComposeViewControllerDelegate" à sua declaração de classe, como: class myClass: UIViewController, MFMailComposeViewControllerDelegate {
Jalakoo
MFMailComposeViewController () return nil for me
ilan
2
Também tendo problemas: 'NSInvalidArgumentException', reason: 'Application tried to present a nil modal view controller on target. O aplicativo trava em alguns dispositivos (iPhone 5, iPhone 6 e iPad Mini)
Spacemonkey
23

No Swift 3 você se certifica de adicionar import MessageUIe precisa estar em conformidade com o 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
fonte
17

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

Substitua [email protected] pelo endereço de e-mail desejado.

Mehdico
fonte
16

Swift 2, com verificação de disponibilidade :

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

Aqui está a aparência do 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
fonte
12

Resposta atualizada de Stephen Groom para Swift 3

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

Aqui está uma atualização para o Swift 4 se você deseja simplesmente abrir o cliente de e-mail por meio de URL:

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

Isso funcionou perfeitamente bem para mim :)

Nii Mantse
fonte
9

Esta é uma solução direta de 3 etapas no Swift.

import MessageUI

Adicionar para conformar o Delegado

MFMailComposeViewControllerDelegate

E apenas crie seu 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)
}
Maria ortega
fonte
4

Você deve tentar enviar com o compositor de e-mail integrado e, se isso falhar, tente com o compartilhamento:

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
fonte
erro: "Este aplicativo não tem permissão para consultar o 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)
}

Observe que nem todos os usuários têm seus dispositivos configurados para enviar e-mails, por isso precisamos verificar o resultado de canSendMail () antes de tentar enviar. Observe também que você precisa capturar o retorno de chamada didFinishWith para descartar a janela de e-mail.

Nishal Solanki
fonte
1

No controlador de visualização de onde você deseja que seu aplicativo de e-mail abra na torneira.

  • Na parte superior do arquivo, importe MessageUI .
  • Coloque esta função dentro do seu 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)
     }
  • Estenda seu controlador de visualização e esteja em conformidade com o MFMailComposeViewControllerDelegate .

  • Coloque esse método e trate da falha, enviando seus e-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
fonte
0

Para aqueles de nós que ainda estão atrasados ​​no Swift 2.3, aqui está a resposta de Gordon em nossa sintaxe:

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

Para Swift 4.2 e superior

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

Dê ao usuário a escolha de várias opções de e-mail (como iCloud, google, yahoo, Outlook.com - se nenhum e-mail estiver pré-configurado em seu telefone) para enviar e-mail.

iHarshil
fonte
1
No meu caso, com o iOS 13, ao chamar UIApplication.shared.open, o sistema operacional sempre mostraria uma caixa de diálogo oferecendo a instalação de Mail.app (oh, e canOpenURL para "mailto" é sempre verdadeiro também), mesmo se houver outros aplicativos de e-mail. Então isso definitivamente não está funcionando.
NeverwinterMoon