etayluz
etayluz

Reputation: 16416

MFMailComposeViewController not sending email or invoking delegate (MFMailComposeViewControllerDelegate)

I have a MFMailComposeViewController setup and presented as such:

class MyViewController: UIViewController {

    // MARK: - Properties
    let composeViewController = MFMailComposeViewController()

    // MARK: - Actions
    @IBAction func didTapSendInEmailButton() {
        composeViewController.mailComposeDelegate = self
        composeViewController.setToRecipients([Constants.contactRecipientEmail])
        composeViewController.setSubject(Constants.contactSubject)
        composeViewController.setMessageBody(Constans.body, isHTML: false)
        present(composeViewController, animated: true, completion: nil)
    }
}

// MARK: - MFMailComposeViewControllerDelegate
extension MyViewController: MFMailComposeViewControllerDelegate {
    private func mailComposeController(_ controller: MFMailComposeViewController,
                                       didFinishWith result: MFMailComposeResult,
                                       error: Error?) {
        switch result {
        case .sent:
            print("Email sent")
        case .saved:
            print("Draft saved")
        case .cancelled:
            print("Email cancelled")
        case  .failed:
            print("Email failed")
        }
        controller.dismiss(animated: true, completion: nil)
    }
}

I'm having this issue:

  1. After pressing "Send" on the composer, the MFMailComposeViewControllerDelegate does NOT get invoked.

What may I be missing?

I'm not able to declare mailComposeController as public:

enter image description here

enter image description here

Upvotes: 2

Views: 1464

Answers (4)

CodeBender
CodeBender

Reputation: 36610

A few minor changes that I will highlight in comments:

import UIKit
import MessageUI

class MyViewController: UIViewController {

    // MARK: - Properties
    let composeViewController = MFMailComposeViewController()

    // MARK: - Actions
    @IBAction func didTapSendInEmailButton() {
        composeViewController.mailComposeDelegate = self
        // Entered a generic email in place of your constant value
        composeViewController.setToRecipients(["[email protected]"])
        // Entered a generic subject in place of your constant value
        composeViewController.setSubject("subject")
        // You have a typo on "Constants" here
        composeViewController.setMessageBody("body", isHTML: false)
        present(composeViewController, animated: true, completion: nil)
    }
}

// MARK: - MFMailComposeViewControllerDelegate
extension MyViewController: MFMailComposeViewControllerDelegate {
    // Removed the private
    func mailComposeController(_ controller: MFMailComposeViewController,
                               didFinishWith result: MFMailComposeResult,
                               error: Error?) {
        switch result {
        case .sent:
            print("Email sent")
        case .saved:
            print("Draft saved")
        case .cancelled:
            print("Email cancelled")
        case  .failed:
            print("Email failed")
        }
        controller.dismiss(animated: true, completion: nil)
    }
}

And my console log shows email sent.

Have you confirmed that your Constants object contains valid data? Perhaps you should print it out or view it at a breakpoint when it arrives here to ensure there are no issues with its contents.

Also, make sure you have a valid email account set up on your device in the first place to send the email for you. If it is a development device, then it may have been reset and lost at some point.

Comparing the Error type in yours: enter image description here

To mine: enter image description here

Notice that the color of Error changes. This means it is using an Error that you have defined, which is scoped to private. You need to break this by renaming your Error to something else. Once that is done, it should resolve your error.

Upvotes: 4

Abhishek Thapliyal
Abhishek Thapliyal

Reputation: 3708

I have also face similar issue recently, My work around is i moved the declaration inside button action

class MyViewController: UIViewController {

    // MARK: - Actions
    @IBAction func didTapSendInEmailButton() {
        let composeViewController = MFMailComposeViewController()
        composeViewController.mailComposeDelegate = self
        composeViewController.setToRecipients([Constants.contactRecipientEmail])
        composeViewController.setSubject(Constants.contactSubject)
        composeViewController.setMessageBody(Constans.body, isHTML: false)
        present(composeViewController, animated: true, completion: nil)
    }
}

// MARK: - MFMailComposeViewControllerDelegate
extension MyViewController: MFMailComposeViewControllerDelegate {
   func mailComposeController(_ controller: MFMailComposeViewController,
                                       didFinishWith result: MFMailComposeResult,
                                       error: Error?) {
        switch result {
        case .sent:
            print("Email sent")
        case .saved:
            print("Draft saved")
        case .cancelled:
            print("Email cancelled")
        case  .failed:
            print("Email failed")
        }
        controller.dismiss(animated: true, completion: nil)
    }
}

Also you don't need to make delegate method private

Upvotes: 2

Abdelahad Darwish
Abdelahad Darwish

Reputation: 6067

I don't know where is your problem

i test Your code it works nice , compiler not in-force me to set delegate as private , Note Email composer not work on simulator just on device

import UIKit
import MessageUI
class MyViewController: UIViewController {

    // MARK: - Properties
    let composeViewController = MFMailComposeViewController()

    // MARK: - Actions
    @IBAction func didTapSendInEmailButton() {

        if MFMailComposeViewController.canSendMail() {
            composeViewController.mailComposeDelegate = self
            composeViewController.setToRecipients(["[email protected]"])
            composeViewController.setSubject("Constants.contactSubjec")
            composeViewController.setMessageBody("Constans.body", isHTML: false)
            present(composeViewController, animated: true, completion: nil)        } else {
        }

    }
}

// MARK: - MFMailComposeViewControllerDelegate
extension MyViewController: MFMailComposeViewControllerDelegate {
    func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {

            switch result {
            case .sent:
                print("Email sent")
            case .saved:
                print("Draft saved")
            case .cancelled:
                print("Email cancelled")
            case  .failed:
                print("Email failed")
            }
            controller.dismiss(animated: true, completion: nil)
    }
}

Upvotes: 2

user9749232
user9749232

Reputation:

extension MyViewController: MFMailComposeViewControllerDelegate {
    private func mailComposeController(_ controller: MFMailComposeViewController,
                                       didFinishWith result: MFMailComposeResult,
                                       error: Error?)

Check your delegate method again, it should be public.

Also make sure your mail account is configured properly.

Upvotes: 2

Related Questions