I'm trying to send an email from with my Swift app. Nothing fancy. Subject. Body. Recipients. I'm doing this like the examples I've seen which is to say NOT using a separate view controller - just a basic vc but specifying MFMailComposeViewControllerDelegate like so:
class MyVC: UIViewController, MFMailComposeViewControllerDelegate
I then have the two methods I see in all the examples:
#IBAction func sendEmail()
{
if MFMailComposeViewController.canSendMail() {
let mail = MFMailComposeViewController()
mail.mailComposeDelegate = self
mail.setSubject(subject)
mail.setToRecipients(recipients)
mail.setMessageBody(content, isHTML: true)
present(mail, animated: true)
} else {
// show failure alert
}
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?)
{
controller.dismiss(animated: true)
}
But when the email gets cancelled (Delete Draft) I get:
[AXRuntimeCommon] AX Lookup problem - errorCode:1100 error:Permission denied portName:'com.apple.iphone.axserver'
No crashing. Emails get sent just fine. But I noticed that the cancelled emails pile up in Mail. The drafts are not being deleted. What am I missing? Does anyone have this kind of thing working?
Related
I'm trying to implement the feature where user can invite friends on App via Messages and Email.
I am using MFMessageComposeViewController for message and MFMailComposeViewController for email.
For messages in delegate method
func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
if result == .sent {
updateAndStoreInvitation(controller.recipients)
}
dismiss(animated: true)
}
we get the recipients and store them to show that this user already invited.
but for email case
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
if result == .sent {
}
dismiss(animated: true)
}
does not provide recipients list.
is there any way to get recipients list in MFMailComposeViewController in delegate method on result == .sent
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])
I have the following code in my app to send an e-Mail:
let ToRecipents = ["recipient here"]
let subject = "subject here"
let MessageBody = "message here"
let mc : MFMailComposeViewController = MFMailComposeViewController()
mc.mailComposeDelegate = self
mc.setToRecipients(ToRecipents)
mc.setSubject(subject)
mc.setMessageBody(MessageBody, isHTML: false)
self.present(mc, animated: true, completion: nil)
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
controller.dismiss(animated: true, completion: nil)
}
I can't seem to get MFMailComposeViewController to dismiss, what am I doing wrong??
In a general way when delegate methods are not called:
• Check if the delegate is set. You do it correctly with mc.mailComposeDelegate = self
• Check if the delegate method you set is compliant with the protocol.
• Check if the delegate method is correctly implemented (that's where lies your issue) in that object you passed as delegate. Read the doc, or remove the method declaration and let the compiler/IDE/XCode autocomplete it for you. In Swift between various tutorials they are often issues because Swift 1, Swift 2, Swift 3/4 have renamed the methods and causing issues, tutorial being focused on a Swift version only.
Your method:
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?)
The method from the documentation:
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?)
Since they are not the same, and the iOS SDK should check the if the delegate responds to the correct method, then yours shouldn't be called because it doesn't match.
I have been using the mail composer in a few of my apps for awhile now and as of recent the mailComposeDelegate no longer gets call.I wasn't sure if this was something to do with the new release of Swift. So, I thought I would ask and see if anyone else is having similar issues.I can present the mail composer but it never gets dismissed due to the delegate not working.
Below is an exact copy of the code I have been using:
func launchFeedback() {
guard MFMailComposeViewController.canSendMail() else {
return
}
let emailTitle = "Feedback"
let messageBody = ""
let toRecipents = ["johnappleseed#icloud.com"]
mailComposer.mailComposeDelegate = self
mailComposer.setSubject(emailTitle)
mailComposer.setMessageBody(messageBody, isHTML: false)
mailComposer.setToRecipients(toRecipents)
self.show(mailComposer, sender: self)
}
func mailComposeController(controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
print(error)
controller.dismiss(animated: true, completion: nil)
}
This is clearly an Xcode bug. The only way to get around this (after searching though StackOverflow life for an hour) was this:
#objc(mailComposeController:didFinishWithResult:error:)
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult,error: NSError?) {
controller.dismiss(animated: true)
}
See the #objc macro before the method implementation. Also note that the last parameter has to be NSError type instead of Error as suggested by Apple documentation (and autocompleted by Xcode)
Swift 3 no longer has unnamed first parameters by default (see this proposal), so you'll need to add an underscore to your function:
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
print(error)
controller.dismiss(animated: true, completion: nil)
}
Swift 4, Xcode 9.1.
My issue was that MFMailComposeViewController was working fine but if you click cancel, dismiss, and then trying to open it one more time both cancel and send button will not fire didFinishWith delegate function.
It was happening because I've declared MFMailComposeViewController as lazy variable and solution was to create new instance of MFMailComposeViewController every time you want to open it.
Problem:
lazy var mailComposeViewController: MFMailComposeViewController = {
let mailComposeViewController = MFMailComposeViewController()
mailComposeViewController.mailComposeDelegate = self
mailComposeViewController.setToRecipients(["example#test.test"])
mailComposeViewController.setSubject("subject")
mailComposeViewController.setMessageBody("test body", isHTML: false)
return mailComposeViewController
}()
Solution:
func createMailComposeViewController() -> MFMailComposeViewController {
let mailComposeViewController = MFMailComposeViewController()
mailComposeViewController.mailComposeDelegate = self
mailComposeViewController.setToRecipients(["example#test.test"])
mailComposeViewController.setSubject("subject")
mailComposeViewController.setMessageBody("test body", isHTML: false)
return mailComposeViewController
}
After wasting 2 good hours, i came to the conclusion that as of Xcode 8.3. MFMailComposeViewController does not work on a mixed swift/objc code base. It pops odd compile errors, which first i thought were due to my stupidity, but no.
This is so frustrating apple. Most of us old timers do have tons of code on obj-c, so a pure swift scenario is close to impossible. So as i move classes to swift i have to deal with extra pain as well.
Adding
#import <MessageUI/MessageUI.h>
to the AppName-Bridging-Header.h did the job !
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)
}