Як відкрити поштовий додаток від Swift


119

Я працюю над простим швидким додатком, де користувач вводить адресу електронної пошти і натискає кнопку, яка відкриє поштовий додаток, із введеною адресою в адресному рядку. Я знаю, як це зробити в Objective-C, але у мене виникають труднощі з тим, щоб він працював у Swift.

Відповіді:


240

Ви можете використовувати прості mailto: посилання в iOS, щоб відкрити поштовий додаток.

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
Можливо, варто додати, що це не працює в тренажері, тільки на пристрої ... Дивіться stackoverflow.com/questions/26052815/…
Пітер

4
тепер вам потрібно додати "!" у другому рядку, для NSURL NSURL (рядок: "mailto: (email)")!
anthonyqz

4
чому це говорить, що це доступно лише на ios 10 або новіших, коли відповідь чітко тридцять років
піт

1
Приклад Swift 4 / iOS 10+: UIApplication.shared.open (URL, параметри: [:], завершенняHandler: nil) Передача порожнього словника для параметрів дає такий же результат, як і виклик openURL.
Лука Вентура

Дякую ... Це дуже допомагає :) :)
Anjali jariwala

61

Хоча інші відповіді вірні, ви ніколи не можете дізнатися, чи встановлено iPhone / iPad, який працює у вашій програмі, програма Apple Mail встановлена чи ні, оскільки користувач може її видалити.

Краще підтримувати кілька клієнтів електронної пошти. Наступний код обробляє надсилання електронної пошти більш витончено. Потік коду:

  • Якщо програма Mail встановлена, відкрийте композитор пошти, попередньо заповнений наданими даними
  • Інакше спробуйте відкрити додаток Gmail, потім Outlook, потім Yahoo пошту, потім Spark, у такому порядку
  • Якщо жоден із цих клієнтів не встановлений, повернення до замовчування mailto:..спонукає користувача встановити додаток Apple Mail.

Код написаний у 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)
        }
    }

Зауважте, що я навмисно пропустив тіло для програми Outlook, оскільки він не в змозі його розібрати.

Ви також повинні додати наступний код, щоб Info.plistподати до списку схем запитів URl, які використовуються.

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>googlegmail</string>
    <string>ms-outlook</string>
    <string>readdle-spark</string>
    <string>ymail</string>
</array>

4
Молодці. Це найбільш повна відповідь і легко розширюється для інших програм для клієнтів електронної пошти. IMHO, я не вважаю прийнятним наприкінці 2019 року просто сказати людині "вибачте, вам не пощастило", якщо вони не використовують програму Apple Mail за замовчуванням, як це пропонує більшість інших рішень. Це виправляє цей дефіцит.
wildcat12

Чи працює цей метод з HTML? Я не можу правильно відобразити його.
Меттью Бредшоу

@MatthewBradshaw ви можете підтримати HTML для композитора пошти за замовчуванням, встановивши isHTMLв наведеному вище коді значення true. Для інших клієнтів, це не представляється можливим, для подальшого читання см stackoverflow.com/questions/5620324/mailto-link-with-html-body
WebMajstr

1
Дякую, це прокидається чудово. Я трохи змінив його, щоб дозволити користувачеві вибирати клієнта за власним уподобанням (я їх заздалегідь фільтрую за допомогою canOpenUrl). Корпус Btw для Microsoft Outlook працює нормально :-)
Філіп

Це геніально! Хтось робив це для SwiftUI?
Аверетт

55

Я не впевнений, чи хочете ви перейти на поштову програму або просто відкрити та надіслати електронний лист. Для останнього варіанту, пов'язаного з кнопкою 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
У мене виникають проблеми, коли функція делегата mailComposeController не викликається.
AustinT

3
Додайте до імпорту "імпорт повідомленняUU" і обов'язково додайте опцію "MFMailComposeViewControllerDelegate" до своєї декларації про клас, наприклад: class myClass: UIViewController, MFMailComposeViewControllerDelegate {
Jalakoo

MFMailComposeViewController () поверне нуль для мене
ilan

2
Також виникають питання: 'NSInvalidArgumentException', reason: 'Application tried to present a nil modal view controller on target.
Збій

23

У Swift 3 ви переконайтеся, що потрібно додати import MessageUIі потрібно відповідати MFMailComposeViewControllerDelegateпротоколу.

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

Протокол:

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

17

Для Swift 4.2+ та 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)
}

Замініть TEST@EXAMPLE.COM на потрібну адресу електронної пошти.


16

Swift 2, перевірка наявності :

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

Ось як виглядає 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

Оновлений відповідь Стівена Жениха за Swift 3

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

10

Ось оновлення для Swift 4, якщо ви просто хочете відкрити поштовий клієнт через URL:

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

Це працювало для мене чудово :)


9

Це пряме рішення з трьох кроків у Swift.

import MessageUI

Додати, щоб відповідати Делегату

MFMailComposeViewControllerDelegate

І просто створіть свій метод:

    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

Спробуйте надіслати повідомлення із вбудованим композитором пошти, а якщо це не вдасться, спробуйте поділитися:

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

помилка: "У цьому додатку заборонено запитувати схему 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)
}

Зауважте, що не всі користувачі налаштовані на свій пристрій для надсилання електронної пошти, тому нам потрібно перевірити результат canSendMail (), перш ніж намагатися надіслати. Зауважте також, що вам потрібно вловити зворотний дзвінок didFinishWith, щоб відхилити вікно пошти.


1

У контролері перегляду, звідки ви хочете, щоб ваш поштовий додаток відкривався на крані.

  • Угорі файлу виконайте імпорт MessageUI .
  • Поставте цю функцію у свій контролер.

    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)
     }
  • Розширіть свій контролер перегляду та відповідайте MFMailComposeViewControllerDelegate .

  • Покладіть цей метод і впорайтеся з невдачею, надсилаючи ваші листи.

    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

Для тих із нас, хто ще відстає від Swift 2.3, ось відповідь Гордона в нашому синтаксисі:

let email = "foo@bar.com"
if let url = NSURL(string: "mailto:\(email)") {
   UIApplication.sharedApplication().openURL(url)
}

0

Для Swift 4.2 і вище

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

Дайте користувачеві вибрати багато варіантів пошти (наприклад, iCloud, google, yahoo, Outlook.com - якщо в його телефоні попередньо не налаштована пошта) для надсилання електронної пошти.


1
У моєму випадку, з iOS 13, під час виклику UIApplication.shared.open, ОС завжди показуватиме діалогове вікно, що пропонує встановити Mail.app (о, і canOpenURL для "mailto" завжди правдивий), навіть якщо є інші поштові програми. Так що це точно не виходить.
NeverwinterMoon
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.