I want to send an email from my Swift application and it works well, it sends the email.
Nevertheless, after sending the email, the layout does not quits. I want to quit the layout after sending the email. I also want this behaviour when I press on Cancel, Remove draft or Save draft button.
This is the code that I have to send the email (after pressing a button):
#IBAction func btnSendEmailAction(_ sender: AnyObject) {
let composeVC = MFMailComposeViewController()
composeVC.mailComposeDelegate = self
composeVC.setToRecipients(["mymail#mail.com"])
composeVC.setSubject("Hello!")
composeVC.setMessageBody("Hello World!", isHTML: false)
self.present(composeVC, animated: true, completion: nil)
}
func mailComposeController(controller: MFMailComposeViewController,
didFinishWithResult result: MFMailComposeResult, error: NSError?) {
switch result {
case MFMailComposeResult.cancelled:
controller.dismiss(animated: true, completion: nil)
break
case MFMailComposeResult.sent:
controller.dismiss(animated: true, completion: nil)
break
case MFMailComposeResult.failed:
controller.dismiss(animated: true, completion: nil)
break
default:
break
}
controller.dismiss(animated: true, completion: nil)
}
but the layout does not quits when I press on Cancel or Sent buttons.
I know that there are a lot of questions related about this problem but I looked a lot of them and this is the code I could get from a mix of some of them. Note that most of them are in Objective instead of Swift (and sometimes the methods does not exist).
Example: iPhone: How to Close MFMailComposeViewController?
Am I missing something on my code? How can I detect Remove draft and Save Draft events?
Thanks in advance!
Looks like you're using swift 3 and not using a valid delegate method. Corrected delegate method is this:
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
switch result {
case .cancelled:
break
case .saved:
break
case .sent:
break
case .failed:
break
}
dismiss(animated: true, completion: nil)
}
Related
I have an application that allows users to send emails by MFMailcomposeViewController.
composeVC.setToRecipients(["email#gmail.com"])
In the same view controller i have a label which is representing the email of the people which is downloaded from Firestore. How can i setToRecipients instead of (["email#gmail.com"]) to (["mailRepresentedLabel#gmail.com"])
I want it to pull the data from mail represented label and add it automatically to the recipient so the end user is not required to add the email to setToRecipient it will be automatically pulled from mailRepresentedLabel
Please help.
My current code is look like this
if !MFMailComposeViewController.canSendMail() {
print("Не удается отправить Имэйл")
return
}
let composeVC = MFMailComposeViewController()
composeVC.mailComposeDelegate = self
// Configure the fields of the interface.
composeVC.setToRecipients(["\(String(describing: mailRepLabel))"])
composeVC.setSubject("Register your client details with us")
composeVC.setMessageBody("Dear agent please register your client with us by replying on that email in order for us to track the information that this client is came with you. if aftersometime the client would like to come without you we will always have the information that this client is came with you and we will send him back to you. Please reply with the following details: Client Name, Passport number Property Managers name.", isHTML: false)
// Present the view controller modally.
self.present(composeVC, animated: true, completion: nil)
print("done")
}
}
extension AgentViewController: MFMailComposeViewControllerDelegate {
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
if let _ = error {
controller.dismiss(animated: true)
return
}
switch result {
case .cancelled:
print("Canceled")
case.failed:
print("Failed to send")
case.saved:
print("Saved")
case.sent:
print("Email Sent")
}
controller.dismiss(animated: true)
}
}```
You can access the text content of your label with the text attribute. So... Something like this?
mailComposer.setToRecipients([mailRepLabel.text])
while sending mail, after tapping send or cancel button view controller stays there and app stalls.
//swift 2.2 ; xcode 7.3.1 ;
if( MFMailComposeViewController.canSendMail() ) {
print("Can send email.")
}
var subjectText = "Verification"
var toReceipients = ["notorious.roman#gmail.com"]
// var msgBody = "Verified"
var mc:MFMailComposeViewController = MFMailComposeViewController()
mc.mailComposeDelegate = self
mc.setSubject(subjectText)
mc.setMessageBody("Verified", isHTML: false)
mc.setToRecipients(toReceipients)
self.presentViewController(mc, animated: true, completion: nil)
}
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
self.dismissViewControllerAnimated(true, completion: nil)
}
Swift 4.0 Update.
Swift 5.0 Update.
Allow me to add something to the discussion...
In Swift 4 and 5 the delegate method slightly changed; As it's posted by you now, won't do any effect and won't get called. It happened to me, drove me crazy!
The Xcode warning suggest three fixes but first two could be misleading. It's just a tiny fix...
Here's the delegate method fixed for Swift 3, 4 and 5:
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
// Dismiss the mail compose view controller.
controller.dismiss(animated: true, completion: nil)
}
Still, Victor's answer should be the correct/accepted one.
Enjoy!
I think #rmaddy answer your question in his comment, nevertheless I going to explain you what's happening. You're trying to dismiss the UIViewController that presents the MFMailComposeViewController not the MFMailComposeViewController.
As Apple specify in his documentation:
The mail compose view controller is not dismissed automatically. When the user taps the buttons to send the email or cancel the interface, the mail compose view controller calls the mailComposeController:didFinishWithResult:error: method of its delegate. Your implementation of that method must dismiss the view controller explicitly.
So you need to set the method in this way:
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
// Dismiss the mail compose view controller.
controller.dismissViewControllerAnimated(true, completion: nil)
}
I hope this help you.
is had an Switch Statement that controls it for me:
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
switch result.rawValue {
case MFMailComposeResult.cancelled.rawValue :
print("Cancelled")
case MFMailComposeResult.failed.rawValue :
print("Failed")
case MFMailComposeResult.saved.rawValue :
print("Saved")
case MFMailComposeResult.sent.rawValue :
print("Sent")
default: break
}
self.dismiss(animated: true, completion: nil)
}
I'm trying to sent a text message and have controller set up like so, but I get an error message 'NSInvalidArgumentException', reason: 'Application tried to present a nil modal view controller on target <Ally.TextMessageController: 0x7fd5361278e0>.' I've made sure that in my storyboard I'm connecting it to TextMessageController so I'm not quite sure what is causing the crash.
class TextMessageController: UIViewController, MFMessageComposeViewControllerDelegate {
var phone: String?
override func viewDidLoad() {
super.viewDidLoad()
print(phone)
var messageVC = MFMessageComposeViewController()
messageVC.body = "Hey I need help, are you available";
messageVC.recipients = ["555555555"]
messageVC.messageComposeDelegate = self;
presentViewController(messageVC, animated: false, completion: nil)
// Do any additional setup after loading the view.
}
func canSendText() -> Bool {
return MFMessageComposeViewController.canSendText()
}
func messageComposeViewController(controller: MFMessageComposeViewController!, didFinishWithResult result: MessageComposeResult) {
self.dismissViewControllerAnimated(true, completion: nil)
switch (result.rawValue) {
case MessageComposeResultCancelled.rawValue:
print("Message was cancelled")
self.dismissViewControllerAnimated(true, completion: nil)
case MessageComposeResultFailed.rawValue:
print("Message failed")
self.dismissViewControllerAnimated(true, completion: nil)
case MessageComposeResultSent.rawValue:
print("Message was sent")
self.dismissViewControllerAnimated(true, completion: nil)
default:
break;
}
}
Here is the error message
'NSInvalidArgumentException', reason: 'Application tried to present a nil modal view controller on target <Ally.TextMessageController: 0x7fd5361278e0>.'
You should first check whether device can send the text message and then only present it. For instance simulator can not send text message thus your code will crash in it. Along with simulator, user’s device may not be set up for the delivery of messages. So perform following check
if messageVC.canSendText() {
presentViewController(messageVC, animated: false, completion: nil)
}
I have done the usual set up of the MFMailComposeViewController() as per Swift Guide
https://developer.apple.com/library/prerelease/ios/documentation/MessageUI/Reference/MFMailComposeViewController_class/
but when I run this then the email appears for a split second, disappears and I get the error message "MailCompositionService quit unexpectedly".
here is the full code
import Foundation
import UIKit
import MessageUI
class ViewController: UIViewController, MFMailComposeViewControllerDelegate {
#IBAction func showEmail(sender: AnyObject) {
let composeVC = MFMailComposeViewController()
composeVC.mailComposeDelegate = self
// Configure the fields of the interface.
composeVC.setToRecipients(["address#example.com"])
composeVC.setSubject("Hello!")
composeVC.setMessageBody("Hello from California!", isHTML: false)
// Present the view controller modally.
self.presentViewController(composeVC, animated: true, completion: nil)
}
func mailComposeController(controller: MFMailComposeViewController,
didFinishWithResult result: MFMailComposeResult, error: NSError?) {
switch result.rawValue {
case MFMailComposeResultCancelled.rawValue:
print("Mail cancelled")
case MFMailComposeResultSaved.rawValue:
print("Mail saved")
case MFMailComposeResultSent.rawValue:
print("Mail sent")
case MFMailComposeResultFailed.rawValue:
print("Mail sent failure: \(error!.localizedDescription)")
default:
break
}
controller.dismissViewControllerAnimated(true, completion: nil)
}}
This is a known bug in the xcode simulator. It should work fine on your device.
Your code is correct. The MFMailComposeViewController component can't be tested in the iOS simulator only in the device.
If you look this Thread in Apple Developer Forums the problem has a ticket in Apple Bug Report but still without any fix.
With manipulation of this tutorial http://www.raywenderlich.com/113772/uisearchcontroller-tutorial
I have a table view displaying people, when the cell is clicked the user is redirected to another view showing their picture and their email. I want to be able to have the user click on the email address and email them. I have researched and found similar tutorials
https://www.andrewcbancroft.com/2014/08/25/send-email-in-app-using-mfmailcomposeviewcontroller-with-swift/
The problem with the tutorial above is when test running the new code the ios simulator pops up an error and wont show the composed email (Maybe a Glitch?)and If the simulator did not give an error I dont know how to display multiple emails based on which person the user selected. Any help on solutions to this problem or any alternative will be great Thanks!!
The simulator will crash when you try to open the mail. Try it on an actual device instead.
To compose a mail do the following
Add these to your class
MFMessageComposeViewControllerDelegate and MFMailComposeViewControllerDelegate
In your didSelectRowAtIndexPath, this is the function called when you presses a row in your tableView. Do the following:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
let candy = candies[indexPath.row]
var mail: MFMailComposeViewController!
// yourArray is the array that you use to populate the tableView
// .mail is the variable in the object (I´m assuming you´re using objects in your array)
let toRecipients = [candy[indexPath.row].email]
let subject = "Feedback"
let body = "<br><br><p>I have a \(UIDevice.currentDevice().modelName).<br> And iOS version \(UIDevice.currentDevice().systemVersion).<br</p>"
mail = MFMailComposeViewController()
mail.mailComposeDelegate = self
mail.setToRecipients(toRecipients)
mail.setSubject(subject)
mail.setMessageBody(body, isHTML: true)
presentViewController(mail, animated: true, completion: nil)
}
The delegate methods below if you need to use them
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
dismissViewControllerAnimated(true, completion: nil)
}
func messageComposeViewController(controller: MFMessageComposeViewController, didFinishWithResult result: MessageComposeResult) {
switch (result.rawValue) {
case MessageComposeResultCancelled.rawValue:
self.dismissViewControllerAnimated(true, completion: nil)
case MessageComposeResultFailed.rawValue:
self.dismissViewControllerAnimated(true, completion: nil)
case MessageComposeResultSent.rawValue:
self.dismissViewControllerAnimated(true, completion: nil)
default:
break;
}
}